test: store Rust source code in rippled, instead of just opaque hex strings (#5653)

This commit is contained in:
Mayukha Vadari
2025-08-15 15:32:36 -04:00
committed by GitHub
parent 77875c9133
commit 293d8e4ddb
33 changed files with 4942 additions and 2357 deletions

View File

@@ -95,3 +95,6 @@ Standard: Cpp11
TabWidth: 8
UseTab: Never
QualifierAlignment: Right
---
Language: Json
IndentWidth: 2

View File

@@ -1708,7 +1708,7 @@ struct Escrow_test : public beast::unit_test::suite
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
static auto wasmHex = ledgerSqnHex;
static auto wasmHex = ledgerSqnWasmHex;
{
// featureSmartEscrow disabled
@@ -1884,7 +1884,7 @@ struct Escrow_test : public beast::unit_test::suite
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
static auto wasmHex = ledgerSqnHex;
static auto wasmHex = ledgerSqnWasmHex;
{
// featureSmartEscrow disabled
@@ -1921,37 +1921,6 @@ struct Escrow_test : public beast::unit_test::suite
ter(temBAD_LIMIT));
}
{
uint32_t const allowance = 5'664;
Env env(*this, features);
env.fund(XRP(5000), alice, carol);
auto const seq = env.seq(alice);
XRPAmount const createFee = env.current()->fees().base + 1000;
// Escrow with FinishFunction + Condition
auto escrowCreate = escrow::create(alice, carol, XRP(1000));
env(escrowCreate,
escrow::finish_function(reqNonexistentField),
escrow::condition(escrow::cb1),
escrow::cancel_time(env.now() + 100s),
fee(createFee));
env.close();
env.close();
// Rejected as wasm code request nonexistent memo field
XRPAmount const txnFees = env.current()->fees().base * 34 + 1000;
env(escrow::finish(alice, alice, seq),
escrow::condition(escrow::cb1),
escrow::fulfillment(escrow::fb1),
escrow::comp_allowance(allowance),
fee(txnFees),
ter(tecWASM_REJECTED));
auto const txMeta = env.meta();
if (BEAST_EXPECT(txMeta->isFieldPresent(sfGasUsed)))
BEAST_EXPECT(txMeta->getFieldU32(sfGasUsed) == allowance);
}
Env env(*this, features);
// Run past the flag ledger so that a Fee change vote occurs and
@@ -2036,7 +2005,7 @@ struct Escrow_test : public beast::unit_test::suite
// Tests whether the ledger index is >= 5
// getLedgerSqn() >= 5}
auto const& wasmHex = ledgerSqnHex;
auto const& wasmHex = ledgerSqnWasmHex;
std::uint32_t const allowance = 71;
{
@@ -2288,7 +2257,7 @@ struct Escrow_test : public beast::unit_test::suite
using namespace std::chrono;
// TODO: create wasm module for all host functions
static auto wasmHex = allHostFunctionsHex;
static auto wasmHex = allHostFunctionsWasmHex;
Account const alice{"alice"};
Account const carol{"carol"};
@@ -2356,7 +2325,7 @@ struct Escrow_test : public beast::unit_test::suite
using namespace std::chrono;
// TODO: create wasm module for all host functions
static auto wasmHex = keyletHostFunctions;
static auto wasmHex = allKeyletsWasmHex;
Account const alice{"alice"};
Account const carol{"carol"};

View File

@@ -57,13 +57,17 @@ struct Wasm_test : public beast::unit_test::suite
{
testcase("Wasm fibo");
auto const ws = boost::algorithm::unhex(fib32Hex);
auto const ws = boost::algorithm::unhex(fibWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "fib", wasmParams(10));
BEAST_EXPECT(re.has_value() && (re->result == 55) && (re->cost == 755));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 55, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 755, std::to_string(re->cost));
}
}
void
@@ -71,22 +75,25 @@ struct Wasm_test : public beast::unit_test::suite
{
testcase("Wasm sha");
auto const ws = boost::algorithm::unhex(sha512PureHex);
auto const ws = boost::algorithm::unhex(sha512PureWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re =
engine.run(wasm, "sha512_process", wasmParams(sha512PureHex));
engine.run(wasm, "sha512_process", wasmParams(sha512PureWasmHex));
BEAST_EXPECT(
re.has_value() && (re->result == 34432) && (re->cost == 157'452));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 34'432, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 157'452, std::to_string(re->cost));
}
}
void
testWasmB58()
{
testcase("Wasm base58");
auto const ws = boost::algorithm::unhex(b58Hex);
auto const ws = boost::algorithm::unhex(b58WasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
@@ -95,38 +102,51 @@ struct Wasm_test : public beast::unit_test::suite
auto const minsz = std::min(
static_cast<std::uint32_t>(512),
static_cast<std::uint32_t>(b58Hex.size()));
auto const s = std::string_view(b58Hex.c_str(), minsz);
static_cast<std::uint32_t>(b58WasmHex.size()));
auto const s = std::string_view(b58WasmHex.c_str(), minsz);
auto const re = engine.run(wasm, "b58enco", wasmParams(outb, s));
BEAST_EXPECT(re.has_value() && re->result && (re->cost == 3'066'129));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 3'066'129, std::to_string(re->cost));
}
}
void
testWasmSP1Verifier()
{
testcase("Wasm sp1 zkproof verifier");
auto const ws = boost::algorithm::unhex(sp1_wasm);
auto const ws = boost::algorithm::unhex(sp1WasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "sp1_groth16_verifier");
BEAST_EXPECT(
re.has_value() && re->result && (re->cost == 4'191'711'969ll));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(
re->cost == 4'191'711'969ll, std::to_string(re->cost));
}
}
void
testWasmBG16Verifier()
{
testcase("Wasm BG16 zkproof verifier");
auto const ws = boost::algorithm::unhex(zkProofHex);
auto const ws = boost::algorithm::unhex(zkProofWasmHex);
Bytes const wasm(ws.begin(), ws.end());
auto& engine = WasmEngine::instance();
auto const re = engine.run(wasm, "bellman_groth16_test");
BEAST_EXPECT(re.has_value() && re->result && (re->cost == 332'205'984));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 332'205'984, std::to_string(re->cost));
}
}
void
@@ -134,7 +154,7 @@ struct Wasm_test : public beast::unit_test::suite
{
testcase("Wasm get ledger sequence");
auto wasmStr = boost::algorithm::unhex(ledgerSqnHex);
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
Bytes wasm(wasmStr.begin(), wasmStr.end());
using namespace test::jtx;
@@ -157,7 +177,10 @@ struct Wasm_test : public beast::unit_test::suite
// code takes 11 gas + 1 getLedgerSqn call
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(!re->result && (re->cost == 44));
{
BEAST_EXPECTS(!re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 44, std::to_string(re->cost));
}
env.close();
env.close();
@@ -170,72 +193,10 @@ struct Wasm_test : public beast::unit_test::suite
// code takes 22 gas + 2 getLedgerSqn calls
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(re->result && (re->cost == 88));
}
void
testWasmCheckJson()
{
testcase("Wasm check json");
using namespace test::jtx;
Env env{*this};
auto const wasmStr = boost::algorithm::unhex(checkJsonHex);
Bytes const wasm(wasmStr.begin(), wasmStr.end());
std::string const funcName("check_accountID");
{
std::string str = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
Bytes data(str.begin(), str.end());
auto re = runEscrowWasm(
wasm, funcName, wasmParams(data), nullptr, -1, env.journal);
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(re.value().result && (re->cost == 838));
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 88, std::to_string(re->cost));
}
{
std::string str = "rHb9CJAWyB4rj91VRWn96DkukG4bwdty00";
Bytes data(str.begin(), str.end());
auto re = runEscrowWasm(
wasm, funcName, wasmParams(data), nullptr, -1, env.journal);
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(!re.value().result && (re->cost == 822));
}
}
void
testWasmCompareJson()
{
testcase("Wasm compare json");
using namespace test::jtx;
Env env{*this};
auto wasmStr = boost::algorithm::unhex(compareJsonHex);
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
std::string funcName("compare_accountID");
std::vector<uint8_t> const tx_data(tx_js.begin(), tx_js.end());
std::vector<uint8_t> const lo_data(lo_js.begin(), lo_js.end());
auto re = runEscrowWasm(
wasm,
funcName,
wasmParams(tx_data, lo_data),
nullptr,
-1,
env.journal);
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(re.value().result && (re->cost == 42'212));
std::vector<uint8_t> const lo_data2(lo_js2.begin(), lo_js2.end());
re = runEscrowWasm(
wasm,
funcName,
wasmParams(tx_data, lo_data2),
nullptr,
-1,
env.journal);
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(!re.value().result && (re->cost == 41'496));
}
void
@@ -281,7 +242,11 @@ struct Wasm_test : public beast::unit_test::suite
// if (res) printf("invokeAdd get the result: %d\n", res.value());
BEAST_EXPECT(re.has_value() && re->result == 6912 && (re->cost == 2));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result == 6'912, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 2, std::to_string(re->cost));
}
}
void
@@ -346,7 +311,7 @@ struct Wasm_test : public beast::unit_test::suite
testcase("escrow wasm devnet test");
std::string const wasmStr =
boost::algorithm::unhex(allHostFunctionsHex);
boost::algorithm::unhex(allHostFunctionsWasmHex);
std::vector<uint8_t> wasm(wasmStr.begin(), wasmStr.end());
using namespace test::jtx;
@@ -357,7 +322,8 @@ struct Wasm_test : public beast::unit_test::suite
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result && (re->cost == 41'132));
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 41'132, std::to_string(re->cost));
}
}
@@ -375,11 +341,11 @@ struct Wasm_test : public beast::unit_test::suite
};
BadTestHostFunctions nfs(env);
auto re =
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100000);
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == -201);
BEAST_EXPECT(re->cost == 5831);
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 5'831, std::to_string(re->cost));
}
}
@@ -400,8 +366,8 @@ struct Wasm_test : public beast::unit_test::suite
runEscrowWasm(wasm, ESCROW_FUNCTION_NAME, {}, &nfs, 100'000);
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result == -201);
BEAST_EXPECT(re->cost == 5831);
BEAST_EXPECTS(re->result == -201, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 5'831, std::to_string(re->cost));
}
}
@@ -412,7 +378,7 @@ struct Wasm_test : public beast::unit_test::suite
TestHostFunctionsSink nfs(env);
std::string funcName("recursive");
auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 1000'000'000);
auto re = runEscrowWasm(wasm, funcName, {}, &nfs, 1'000'000'000);
BEAST_EXPECT(!re && re.error());
// std::cout << "bad case (deep recursion) result " << re.error()
// << std::endl;
@@ -438,7 +404,7 @@ struct Wasm_test : public beast::unit_test::suite
}
{
auto wasmStr = boost::algorithm::unhex(ledgerSqnHex);
auto wasmStr = boost::algorithm::unhex(ledgerSqnWasmHex);
Bytes wasm(wasmStr.begin(), wasmStr.end());
TestLedgerDataProvider ledgerDataProvider(&env);
@@ -471,7 +437,7 @@ struct Wasm_test : public beast::unit_test::suite
Env env(*this);
{
std::string const wasmHex = allHostFunctionsHex;
std::string const wasmHex = allHostFunctionsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
@@ -493,7 +459,8 @@ struct Wasm_test : public beast::unit_test::suite
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result && (re->cost == 872));
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 872, std::to_string(re->cost));
}
env.close();
@@ -506,7 +473,7 @@ struct Wasm_test : public beast::unit_test::suite
env.close();
{
std::string const wasmHex = allHostFunctionsHex;
std::string const wasmHex = allHostFunctionsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
@@ -526,7 +493,8 @@ struct Wasm_test : public beast::unit_test::suite
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECT(re->result && (re->cost == 41'132));
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 41'132, std::to_string(re->cost));
}
env.close();
@@ -544,13 +512,17 @@ struct Wasm_test : public beast::unit_test::suite
Env env(*this);
{
std::string const wasmHex = floatHex;
std::string const wasmHex = floatTestsWasmHex;
std::string const wasmStr = boost::algorithm::unhex(wasmHex);
std::vector<uint8_t> const wasm(wasmStr.begin(), wasmStr.end());
TestHostFunctions hf(env, 0);
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
BEAST_EXPECT(re && re->result && (re->cost == 91'412));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 91'412, std::to_string(re->cost));
}
env.close();
}
@@ -561,7 +533,11 @@ struct Wasm_test : public beast::unit_test::suite
TestHostFunctions hf(env, 0);
auto re = runEscrowWasm(wasm, funcName, {}, &hf, 100'000);
BEAST_EXPECT(re && re->result && (re->cost == 6'533));
if (BEAST_EXPECT(re.has_value()))
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 6'533, std::to_string(re->cost));
}
env.close();
}
}
@@ -677,7 +653,7 @@ struct Wasm_test : public beast::unit_test::suite
// beast::severities::kTrace};
Env env{*this};
auto const wasmStr = boost::algorithm::unhex(codecovWasm);
auto const wasmStr = boost::algorithm::unhex(codecovTestsWasmHex);
Bytes const wasm(wasmStr.begin(), wasmStr.end());
std::string const funcName("finish");
TestHostFunctions hfs(env, 0);
@@ -686,7 +662,10 @@ struct Wasm_test : public beast::unit_test::suite
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
if (BEAST_EXPECT(re.has_value()))
BEAST_EXPECT(re->result);
{
BEAST_EXPECTS(re->result, std::to_string(re->result));
BEAST_EXPECTS(re->cost == 100'784, std::to_string(re->cost));
}
}
void
@@ -706,7 +685,10 @@ struct Wasm_test : public beast::unit_test::suite
// f32 set constant, opcode disabled exception
auto const re =
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
BEAST_EXPECT(!re && re.error() == tecFAILED_PROCESSING);
if (BEAST_EXPECT(!re.has_value()))
{
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
}
}
{
@@ -714,7 +696,10 @@ struct Wasm_test : public beast::unit_test::suite
wasm[0x117] = 0x92;
auto const re =
runEscrowWasm(wasm, funcName, {}, &hfs, 1'000'000, env.journal);
BEAST_EXPECT(!re && re.error() == tecFAILED_PROCESSING);
if (BEAST_EXPECT(!re.has_value()))
{
BEAST_EXPECT(re.error() == tecFAILED_PROCESSING);
}
}
}
@@ -726,8 +711,6 @@ struct Wasm_test : public beast::unit_test::suite
testGetDataHelperFunctions();
testWasmLib();
testBadWasm();
testWasmCheckJson();
testWasmCompareJson();
testWasmLedgerSqn();
testWasmFib();

3
src/test/app/wasm_fixtures/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
**/target
**/debug
*.wasm

View File

@@ -0,0 +1,15 @@
# 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-std",
]
[[package]]
name = "xrpl-std"
version = "0.0.1"
source = "git+https://github.com/ripple/craft.git?branch=main#94fb247e0c21b9e7fecb91ce71ef7f74ef4a7931"

View File

@@ -0,0 +1,21 @@
[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/craft.git", branch = "main", package = "xrpl-std" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
opt-level = "z"
lto = true

View File

@@ -0,0 +1,828 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
//
// Host Functions Test
// Tests 26 host functions (across 7 categories)
//
// With craft you can run this test with:
// craft test --project host_functions_test --test-case host_functions_test
//
// Amount Format Update:
// - XRP amounts now return as 8-byte serialized rippled objects
// - IOU and MPT amounts return in variable-length serialized format
// - Format details: https://xrpl.org/docs/references/protocol/binary-format#amount-fields
//
// Error Code Ranges:
// -100 to -199: Ledger Header Functions (3 functions)
// -200 to -299: Transaction Data Functions (5 functions)
// -300 to -399: Current Ledger Object Functions (4 functions)
// -400 to -499: Any Ledger Object Functions (5 functions)
// -500 to -599: Keylet Generation Functions (4 functions)
// -600 to -699: Utility Functions (4 functions)
// -700 to -799: Data Update Functions (1 function)
//
use xrpl_std::core::current_tx::escrow_finish::EscrowFinish;
use xrpl_std::core::current_tx::traits::TransactionCommonFields;
use xrpl_std::host::trace::{DataRepr, trace_data, trace_num};
use xrpl_std::host::*;
use xrpl_std::sfield;
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace_data("=== HOST FUNCTIONS TEST ===", &[], DataRepr::AsHex);
let _ = trace_data("Testing 26 host functions", &[], DataRepr::AsHex);
// 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_data(
"SUCCESS: All host function tests passed!",
&[],
DataRepr::AsHex,
);
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_data(
"--- Category 1: Ledger Header Functions ---",
&[],
DataRepr::AsHex,
);
// Test 1.1: get_ledger_sqn() - should return current ledger sequence number
let mut ledger_sqn_buffer = [0u8; 8];
let sqn_result =
unsafe { get_ledger_sqn(ledger_sqn_buffer.as_mut_ptr(), ledger_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 _ = trace_num("Ledger sequence number bytes:", sqn_result as i64);
let _ = trace_data(
"Ledger sqn data:",
&ledger_sqn_buffer[..sqn_result as usize],
DataRepr::AsHex,
);
// Test 1.2: get_parent_ledger_time() - should return parent ledger timestamp
let mut time_buffer = [0u8; 8];
let time_result =
unsafe { get_parent_ledger_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 _ = trace_num("Parent ledger time bytes:", time_result as i64);
let _ = trace_data(
"Parent time data:",
&time_buffer[..time_result as usize],
DataRepr::AsHex,
);
// Test 1.3: get_parent_ledger_hash() - should return parent ledger hash (32 bytes)
let mut hash_buffer = [0u8; 32];
let hash_result =
unsafe { get_parent_ledger_hash(hash_buffer.as_mut_ptr(), hash_buffer.len()) };
if hash_result != 32 {
let _ = trace_num(
"ERROR: get_parent_ledger_hash wrong length:",
hash_result as i64,
);
return -103; // Parent ledger hash test failed - should be exactly 32 bytes
}
let _ = trace_data("Parent ledger hash:", &hash_buffer, DataRepr::AsHex);
let _ = trace_data("SUCCESS: Ledger header functions", &[], DataRepr::AsHex);
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_data(
"--- Category 2: Transaction Data Functions ---",
&[],
DataRepr::AsHex,
);
// 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 {
get_tx_field(
sfield::Account,
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_data("Transaction Account:", &account_buffer, DataRepr::AsHex);
// 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 { get_tx_field(sfield::Fee, fee_buffer.as_mut_ptr(), fee_buffer.len()) };
if fee_len != 8 {
let _ = trace_num(
"ERROR: get_tx_field(Fee) wrong length (expected 8 bytes for XRP):",
fee_len as i64,
);
return -202; // Fee field test failed - XRP amounts should be exactly 8 bytes
}
let _ = trace_num("Transaction Fee length:", fee_len as i64);
let _ = trace_data(
"Transaction Fee (serialized XRP amount):",
&fee_buffer,
DataRepr::AsHex,
);
// Test with Sequence field (required, 4 bytes uint32)
let mut seq_buffer = [0u8; 4];
let seq_len =
unsafe { get_tx_field(sfield::Sequence, seq_buffer.as_mut_ptr(), seq_buffer.len()) };
if seq_len != 4 {
let _ = trace_num(
"ERROR: get_tx_field(Sequence) wrong length:",
seq_len as i64,
);
return -203; // Sequence field test failed
}
let _ = trace_data("Transaction Sequence:", &seq_buffer, DataRepr::AsHex);
// NOTE: get_tx_field2() through get_tx_field6() have been deprecated.
// Use get_tx_field() with appropriate parameters for all transaction field access.
// Test 2.2: get_tx_nested_field() - Nested field access with locator
let locator = [0x01, 0x00]; // Simple locator for first element
let mut nested_buffer = [0u8; 32];
let nested_result = unsafe {
get_tx_nested_field(
locator.as_ptr(),
locator.len(),
nested_buffer.as_mut_ptr(),
nested_buffer.len(),
)
};
if nested_result < 0 {
let _ = trace_num(
"INFO: get_tx_nested_field not applicable:",
nested_result as i64,
);
// Expected - locator may not match transaction structure
} else {
let _ = trace_num("Nested field length:", nested_result as i64);
let _ = trace_data(
"Nested field:",
&nested_buffer[..nested_result as usize],
DataRepr::AsHex,
);
}
// Test 2.3: get_tx_array_len() - Get array length
let signers_len = unsafe { get_tx_array_len(sfield::Signers) };
let _ = trace_num("Signers array length:", signers_len as i64);
let memos_len = unsafe { get_tx_array_len(sfield::Memos) };
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 { get_tx_nested_array_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_data("SUCCESS: Transaction data functions", &[], DataRepr::AsHex);
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_data(
"--- Category 3: Current Ledger Object Functions ---",
&[],
DataRepr::AsHex,
);
// 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 {
get_current_ledger_obj_field(
sfield::Balance,
balance_buffer.as_mut_ptr(),
balance_buffer.len(),
)
};
if balance_result <= 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_field(Balance) failed (may be expected):",
balance_result as i64,
);
// This might fail if current ledger object doesn't have balance field
} else if balance_result == 8 {
let _ = trace_num(
"Current object balance length (XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance (serialized XRP amount):",
&balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Current object balance length (non-XRP amount):",
balance_result as i64,
);
let _ = trace_data(
"Current object balance:",
&balance_buffer[..balance_result as usize],
DataRepr::AsHex,
);
}
// Test with Account field
let mut current_account_buffer = [0u8; 20];
let current_account_result = unsafe {
get_current_ledger_obj_field(
sfield::Account,
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_data(
"Current ledger object account:",
&current_account_buffer[..current_account_result as usize],
DataRepr::AsHex,
);
}
// Test 3.2: get_current_ledger_obj_nested_field() - Nested field access
let locator = [0x01, 0x00]; // Simple locator
let mut current_nested_buffer = [0u8; 32];
let current_nested_result = unsafe {
get_current_ledger_obj_nested_field(
locator.as_ptr(),
locator.len(),
current_nested_buffer.as_mut_ptr(),
current_nested_buffer.len(),
)
};
if current_nested_result < 0 {
let _ = trace_num(
"INFO: get_current_ledger_obj_nested_field not applicable:",
current_nested_result as i64,
);
} else {
let _ = trace_num("Current nested field length:", current_nested_result as i64);
let _ = trace_data(
"Current nested field:",
&current_nested_buffer[..current_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 3.3: get_current_ledger_obj_array_len() - Array length in current object
let current_array_len = unsafe { get_current_ledger_obj_array_len(sfield::Signers) };
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 { get_current_ledger_obj_nested_array_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_data(
"SUCCESS: Current ledger object functions",
&[],
DataRepr::AsHex,
);
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_data(
"--- Category 4: Any Ledger Object Functions ---",
&[],
DataRepr::AsHex,
);
// 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 {
account_keylet(
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: account_keylet failed for caching test:",
keylet_result as i64,
);
return -401; // Keylet generation failed for caching test
}
let cache_result =
unsafe { cache_ledger_obj(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 {
get_ledger_obj_field(
1,
sfield::Balance,
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, 0x00];
let nested_result = unsafe {
get_ledger_obj_nested_field(
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 { get_ledger_obj_array_len(1, sfield::Signers) };
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 { get_ledger_obj_nested_array_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_data(
"SUCCESS: Any ledger object functions (interface tested)",
&[],
DataRepr::AsHex,
);
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 {
get_ledger_obj_field(
slot,
sfield::Balance,
cached_balance_buffer.as_mut_ptr(),
cached_balance_buffer.len(),
)
};
if cached_balance_result <= 0 {
let _ = trace_num(
"INFO: get_ledger_obj_field(Balance) failed:",
cached_balance_result as i64,
);
} else if cached_balance_result == 8 {
let _ = trace_num(
"Cached object balance length (XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance (serialized XRP amount):",
&cached_balance_buffer,
DataRepr::AsHex,
);
} else {
let _ = trace_num(
"Cached object balance length (non-XRP amount):",
cached_balance_result as i64,
);
let _ = trace_data(
"Cached object balance:",
&cached_balance_buffer[..cached_balance_result as usize],
DataRepr::AsHex,
);
}
// Test 4.3: get_ledger_obj_nested_field() - Nested field from cached object
let locator = [0x01, 0x00];
let mut cached_nested_buffer = [0u8; 32];
let cached_nested_result = unsafe {
get_ledger_obj_nested_field(
slot,
locator.as_ptr(),
locator.len(),
cached_nested_buffer.as_mut_ptr(),
cached_nested_buffer.len(),
)
};
if cached_nested_result < 0 {
let _ = trace_num(
"INFO: get_ledger_obj_nested_field not applicable:",
cached_nested_result as i64,
);
} else {
let _ = trace_num("Cached nested field length:", cached_nested_result as i64);
let _ = trace_data(
"Cached nested field:",
&cached_nested_buffer[..cached_nested_result as usize],
DataRepr::AsHex,
);
}
// Test 4.4: get_ledger_obj_array_len() - Array length from cached object
let cached_array_len = unsafe { get_ledger_obj_array_len(slot, sfield::Signers) };
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 { get_ledger_obj_nested_array_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_data("SUCCESS: Any ledger object functions", &[], DataRepr::AsHex);
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_data(
"--- Category 5: Keylet Generation Functions ---",
&[],
DataRepr::AsHex,
);
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
// Test 5.1: account_keylet() - Generate keylet for account
let mut account_keylet_buffer = [0u8; 32];
let account_keylet_result = unsafe {
account_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
account_keylet_buffer.as_mut_ptr(),
account_keylet_buffer.len(),
)
};
if account_keylet_result != 32 {
let _ = trace_num(
"ERROR: account_keylet failed:",
account_keylet_result as i64,
);
return -501; // Account keylet generation failed
}
let _ = trace_data("Account keylet:", &account_keylet_buffer, DataRepr::AsHex);
// Test 5.2: credential_keylet() - Generate keylet for credential
let mut credential_keylet_buffer = [0u8; 32];
let credential_keylet_result = unsafe {
credential_keylet(
account_id.0.as_ptr(), // Subject
account_id.0.len(),
account_id.0.as_ptr(), // Issuer - same account for test
account_id.0.len(),
b"TestType".as_ptr(), // Credential type
9usize, // Length of "TestType"
credential_keylet_buffer.as_mut_ptr(),
credential_keylet_buffer.len(),
)
};
if credential_keylet_result <= 0 {
let _ = trace_num(
"INFO: credential_keylet failed (expected - interface issue):",
credential_keylet_result as i64,
);
// This is expected to fail due to unusual parameter types
} else {
let _ = trace_data(
"Credential keylet:",
&credential_keylet_buffer[..credential_keylet_result as usize],
DataRepr::AsHex,
);
}
// Test 5.3: escrow_keylet() - Generate keylet for escrow
let mut escrow_keylet_buffer = [0u8; 32];
let escrow_keylet_result = unsafe {
escrow_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
1000, // Sequence number
escrow_keylet_buffer.as_mut_ptr(),
escrow_keylet_buffer.len(),
)
};
if escrow_keylet_result != 32 {
let _ = trace_num("ERROR: escrow_keylet failed:", escrow_keylet_result as i64);
return -503; // Escrow keylet generation failed
}
let _ = trace_data("Escrow keylet:", &escrow_keylet_buffer, DataRepr::AsHex);
// Test 5.4: oracle_keylet() - Generate keylet for oracle
let mut oracle_keylet_buffer = [0u8; 32];
let oracle_keylet_result = unsafe {
oracle_keylet(
account_id.0.as_ptr(),
account_id.0.len(),
42, // Document ID
oracle_keylet_buffer.as_mut_ptr(),
oracle_keylet_buffer.len(),
)
};
if oracle_keylet_result != 32 {
let _ = trace_num("ERROR: oracle_keylet failed:", oracle_keylet_result as i64);
return -504; // Oracle keylet generation failed
}
let _ = trace_data("Oracle keylet:", &oracle_keylet_buffer, DataRepr::AsHex);
let _ = trace_data("SUCCESS: Keylet generation functions", &[], DataRepr::AsHex);
0
}
/// Test Category 6: Utility Functions (4 functions)
/// Tests utility functions for hashing, NFT access, and tracing
fn test_utility_functions() -> i32 {
let _ = trace_data(
"--- Category 6: Utility Functions ---",
&[],
DataRepr::AsHex,
);
// 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 {
compute_sha512_half(
test_data.as_ptr(),
test_data.len(),
hash_output.as_mut_ptr(),
hash_output.len(),
)
};
if hash_result != 32 {
let _ = trace_num("ERROR: compute_sha512_half failed:", hash_result as i64);
return -601; // SHA512 half computation failed
}
let _ = trace_data("Input data:", test_data, DataRepr::AsHex);
let _ = trace_data("SHA512 half hash:", &hash_output, DataRepr::AsHex);
// Test 6.2: get_nft() - NFT data retrieval
let escrow_finish = EscrowFinish;
let account_id = escrow_finish.get_account().unwrap();
let nft_id = [0u8; 32]; // Dummy NFT ID for testing
let mut nft_buffer = [0u8; 256];
let nft_result = unsafe {
get_nft(
account_id.0.as_ptr(),
account_id.0.len(),
nft_id.as_ptr(),
nft_id.len(),
nft_buffer.as_mut_ptr(),
nft_buffer.len(),
)
};
if nft_result <= 0 {
let _ = trace_num(
"INFO: get_nft failed (expected - no such NFT):",
nft_result as i64,
);
// This is expected - test account likely doesn't own the dummy NFT
} else {
let _ = trace_num("NFT data length:", nft_result as i64);
let _ = trace_data(
"NFT data:",
&nft_buffer[..nft_result as usize],
DataRepr::AsHex,
);
}
// Test 6.3: trace() - Debug logging with data
let trace_message = b"Test trace message";
let trace_data_payload = b"payload";
let trace_result = unsafe {
trace(
trace_message.as_ptr(),
trace_message.len(),
trace_data_payload.as_ptr(),
trace_data_payload.len(),
1, // as_hex = true
)
};
if trace_result < 0 {
let _ = trace_num("ERROR: trace() failed:", trace_result as i64);
return -603; // Trace function failed
}
let _ = trace_num("Trace function bytes written:", trace_result as i64);
// Test 6.4: trace_num() - Debug logging with number
let test_number = 42i64;
let trace_num_result = trace_num("Test number trace", test_number);
use xrpl_std::host::Result;
match trace_num_result {
Result::Ok(_) => {
let _ = trace_num("Trace_num function succeeded", 0);
}
Result::Err(_) => {
let _ = trace_num("ERROR: trace_num() failed:", -604);
return -604; // Trace number function failed
}
}
let _ = trace_data("SUCCESS: Utility functions", &[], DataRepr::AsHex);
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_data(
"--- Category 7: Data Update Functions ---",
&[],
DataRepr::AsHex,
);
// 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 { update_data(update_payload.as_ptr(), update_payload.len()) };
if update_result != 0 {
let _ = trace_num("ERROR: update_data failed:", update_result as i64);
return -701; // Data update failed
}
let _ = trace_data(
"Successfully updated ledger entry with:",
update_payload,
DataRepr::AsHex,
);
let _ = trace_data("SUCCESS: Data update functions", &[], DataRepr::AsHex);
0
}

View File

@@ -0,0 +1,15 @@
# 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-std",
]
[[package]]
name = "xrpl-std"
version = "0.0.1"
source = "git+https://github.com/ripple/craft.git?branch=main#94fb247e0c21b9e7fecb91ce71ef7f74ef4a7931"

View File

@@ -0,0 +1,21 @@
[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/craft.git", branch = "main", package = "xrpl-std" }
[profile.dev]
panic = "abort"

View File

@@ -0,0 +1,156 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use crate::host::{Result, Result::Err, Result::Ok};
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::types::amount::currency_code::CurrencyCode;
use xrpl_std::core::types::keylets;
use xrpl_std::host;
use xrpl_std::host::trace::{trace, trace_data, trace_num, DataRepr};
use xrpl_std::sfield;
#[unsafe(no_mangle)]
pub fn object_exists(
keylet_result: Result<keylets::KeyletBytes>,
keylet_type: &str,
field: i32,
) -> Result<bool> {
match keylet_result {
Ok(keylet) => {
let _ = trace_data(keylet_type, &keylet, DataRepr::AsHex);
let slot = unsafe { host::cache_ledger_obj(keylet.as_ptr(), keylet.len(), 0) };
if slot <= 0 {
let _ = trace_num("Error: ", slot.into());
return Err(host::Error::NoFreeSlots);
}
if field == 0 {
let new_field = sfield::PreviousTxnID;
let _ = trace_num("Getting field: ", new_field.into());
match ledger_object::get_hash_256_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_account_id_field(slot, 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);
}
}
}
Ok(true)
}
Err(error) => {
let _ = trace_num("Error getting keylet: ", error.into());
Err(error)
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
let _ = trace("$$$$$ STARTING WASM EXECUTION $$$$$");
let escrow: CurrentEscrow = get_current_escrow();
let account = escrow.get_account().unwrap_or_panic();
let _ = trace_data(" Account:", &account.0, DataRepr::AsHex);
let destination = escrow.get_destination().unwrap_or_panic();
let _ = trace_data(" Destination:", &destination.0, DataRepr::AsHex);
macro_rules! check_object_exists {
($keylet:expr, $type:expr, $field:expr) => {
match object_exists($keylet, $type, $field) {
Ok(exists) => {
if exists {
let _ = trace(concat!(
$type,
" object exists, proceeding with escrow finish."
));
} else {
let _ = trace(concat!(
$type,
" object does not exist, aborting escrow finish."
));
return 0;
}
}
Err(error) => return error.code(),
}
};
}
let account_keylet = keylets::account_keylet(&account);
check_object_exists!(account_keylet, "Account", sfield::Account);
let mut seq = 5;
let currency_code: &[u8; 3] = b"USD";
let currency: CurrencyCode = CurrencyCode::from(*currency_code);
let line_keylet = keylets::line_keylet(&account, &destination, &currency);
check_object_exists!(line_keylet, "Trustline", sfield::Generic);
seq += 1;
let check_keylet = keylets::check_keylet(&account, seq);
check_object_exists!(check_keylet, "Check", sfield::Account);
seq += 1;
let cred_type: &[u8] = b"termsandconditions";
let credential_keylet = keylets::credential_keylet(&account, &account, cred_type);
check_object_exists!(credential_keylet, "Credential", sfield::Subject);
seq += 1;
let delegate_keylet = keylets::delegate_keylet(&account, &destination);
check_object_exists!(delegate_keylet, "Delegate", sfield::Account);
seq += 1;
let deposit_preauth_keylet = keylets::deposit_preauth_keylet(&account, &destination);
check_object_exists!(deposit_preauth_keylet, "DepositPreauth", sfield::Account);
seq += 1;
let did_keylet = keylets::did_keylet(&account);
check_object_exists!(did_keylet, "DID", sfield::Account);
seq += 1;
let escrow_keylet = keylets::escrow_keylet(&account, seq);
check_object_exists!(escrow_keylet, "Escrow", sfield::Account);
seq += 1;
let nft_offer_keylet = keylets::nft_offer_keylet(&destination, 4);
check_object_exists!(nft_offer_keylet, "NFTokenOffer", sfield::Owner);
let offer_keylet = keylets::offer_keylet(&account, seq);
check_object_exists!(offer_keylet, "Offer", sfield::Account);
seq += 1;
let paychan_keylet = keylets::paychan_keylet(&account, &destination, seq);
check_object_exists!(paychan_keylet, "PayChannel", sfield::Account);
seq += 1;
let signers_keylet = keylets::signers_keylet(&account);
check_object_exists!(signers_keylet, "SignerList", sfield::Generic);
seq += 1;
seq += 1; // ticket sequence number is one greater
let ticket_keylet = keylets::ticket_keylet(&account, seq);
check_object_exists!(ticket_keylet, "Ticket", sfield::Account);
// seq += 1;
1 // All keylets exist, finish the escrow.
}

View File

@@ -0,0 +1,73 @@
#include <stdint.h>
static char const b58digits_ordered[] =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
uint8_t e_data[32 * 1024];
void*
allocate(int sz)
{
static int idx = 0;
if (idx >= 32)
return 0;
if (sz > 1024)
return 0;
return &e_data[idx++ << 10];
}
void
deallocate(void* p)
{
}
extern int32_t
b58enco(char* b58, int32_t b58sz, void const* data, int32_t binsz)
{
uint8_t const* bin = data;
int32_t carry;
int32_t i, j, high, zcount = 0;
int32_t size;
while (zcount < binsz && !bin[zcount])
++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t* buf = allocate(size);
if (!buf)
return 0;
// memset(buf, 0, size);
for (i = 0; i < size; ++i)
buf[i] = 0;
for (i = zcount, high = size - 1; i < binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
if (!j)
break;
}
}
for (j = 0; j < size && !buf[j]; ++j)
;
if (b58sz <= zcount + size - j)
return 0;
if (zcount)
{
// memset(b58, '1', zcount);
for (i = 0; i < zcount; ++i)
b58[i] = '1';
}
for (i = zcount; j < size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
return i + 1;
}

View File

@@ -0,0 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "codecov_tests"
version = "0.0.1"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.0.1"
source = "git+https://github.com/ripple/craft.git?branch=main#94fb247e0c21b9e7fecb91ce71ef7f74ef4a7931"

View File

@@ -0,0 +1,19 @@
[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/craft.git", branch = "main", package = "xrpl-std" }

View File

@@ -0,0 +1,47 @@
//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 get_ledger_sqn(out_buff_ptr: i32, out_buff_len: i32) -> i32;
pub fn cache_ledger_obj(keylet_ptr: i32, keylet_len: i32, cache_num: i32) -> i32;
pub fn get_tx_nested_array_len(locator_ptr: i32, locator_len: i32) -> i32;
pub fn account_keylet(
account_ptr: i32,
account_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn line_keylet(
account1_ptr: *const u8,
account1_len: usize,
account2_ptr: *const u8,
account2_len: usize,
currency_ptr: i32,
currency_len: i32,
out_buff_ptr: *mut u8,
out_buff_len: usize,
) -> i32;
pub fn trace_num(msg_read_ptr: i32, msg_read_len: i32, number: i64) -> i32;
}

View File

@@ -0,0 +1,953 @@
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use core::panic;
use xrpl_std::core::current_tx::escrow_finish::{EscrowFinish, get_current_escrow_finish};
use xrpl_std::core::current_tx::traits::TransactionCommonFields;
use xrpl_std::core::error_codes;
use xrpl_std::core::locator::Locator;
use xrpl_std::core::types::keylets;
use xrpl_std::host;
use xrpl_std::host::trace::{trace, trace_num as trace_number};
use xrpl_std::sfield;
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_number("TEST FAILED", code.into());
panic!("Error code: {}", code);
}
}
}
fn with_buffer<const N: usize, F, R>(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 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.
// ########################################
with_buffer::<4, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_sqn(ptr, len) },
4,
"get_ledger_sqn",
)
});
with_buffer::<4, _, _>(|ptr, len| {
check_result(
unsafe { host::get_parent_ledger_time(ptr, len) },
4,
"get_parent_ledger_time",
);
});
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe { host::get_parent_ledger_hash(ptr, len) },
32,
"get_parent_ledger_hash",
);
});
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_account_hash(ptr, len) },
32,
"get_ledger_account_hash",
);
});
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_tx_hash(ptr, len) },
32,
"get_ledger_tx_hash",
);
});
check_result(unsafe { host::get_base_fee() }, 10, "get_base_fee");
let amendment_name: &[u8] = b"test_amendment";
let amendment_id: [u8; 32] = [1; 32];
check_result(
unsafe { host::amendment_enabled(amendment_name.as_ptr(), amendment_name.len()) },
1,
"amendment_enabled",
);
check_result(
unsafe { host::amendment_enabled(amendment_id.as_ptr(), amendment_id.len()) },
1,
"amendment_enabled",
);
let tx: EscrowFinish = get_current_escrow_finish();
let account = tx.get_account().unwrap_or_panic(); // get_tx_field under the hood
let keylet = keylets::account_keylet(&account).unwrap_or_panic(); // account_keylet under the hood
check_result(
unsafe { host::cache_ledger_obj(keylet.as_ptr(), keylet.len(), 0) },
1,
"cache_ledger_obj",
);
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe { host::get_current_ledger_obj_field(sfield::Account, ptr, len) },
20,
"get_current_ledger_obj_field",
);
});
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_obj_field(1, sfield::Account, ptr, len) },
20,
"get_ledger_obj_field",
);
});
let mut locator = Locator::new();
locator.pack(sfield::Account);
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe { host::get_tx_nested_field(locator.as_ptr(), locator.len(), ptr, len) },
20,
"get_tx_nested_field",
);
});
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe {
host::get_current_ledger_obj_nested_field(locator.as_ptr(), locator.len(), ptr, len)
},
20,
"get_current_ledger_obj_nested_field",
);
});
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe {
host::get_ledger_obj_nested_field(1, locator.as_ptr(), locator.len(), ptr, len)
},
20,
"get_ledger_obj_nested_field",
);
});
check_result(
unsafe { host::get_tx_array_len(sfield::Memos) },
32,
"get_tx_array_len",
);
check_result(
unsafe { host::get_current_ledger_obj_array_len(sfield::Memos) },
32,
"get_current_ledger_obj_array_len",
);
check_result(
unsafe { host::get_ledger_obj_array_len(1, sfield::Memos) },
32,
"get_ledger_obj_array_len",
);
check_result(
unsafe { host::get_tx_nested_array_len(locator.as_ptr(), locator.len()) },
32,
"get_tx_nested_array_len",
);
check_result(
unsafe { host::get_current_ledger_obj_nested_array_len(locator.as_ptr(), locator.len()) },
32,
"get_current_ledger_obj_nested_array_len",
);
check_result(
unsafe { host::get_ledger_obj_nested_array_len(1, locator.as_ptr(), locator.len()) },
32,
"get_ledger_obj_nested_array_len",
);
check_result(
unsafe { host::update_data(account.0.as_ptr(), account.0.len()) },
0,
"update_data",
);
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe { host::compute_sha512_half(locator.as_ptr(), locator.len(), ptr, len) },
32,
"compute_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::get_nft(
account.0.as_ptr(),
account.0.len(),
nft_id.as_ptr(),
nft_id.len(),
ptr,
len,
)
},
18,
"get_nft",
)
});
with_buffer::<20, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_issuer(nft_id.as_ptr(), nft_id.len(), ptr, len) },
20,
"get_nft_issuer",
)
});
with_buffer::<4, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_taxon(nft_id.as_ptr(), nft_id.len(), ptr, len) },
4,
"get_nft_taxon",
)
});
check_result(
unsafe { host::get_nft_flags(nft_id.as_ptr(), nft_id.len()) },
8,
"get_nft_flags",
);
check_result(
unsafe { host::get_nft_transfer_fee(nft_id.as_ptr(), nft_id.len()) },
10,
"get_nft_transfer_fee",
);
with_buffer::<4, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_serial(nft_id.as_ptr(), nft_id.len(), ptr, len) },
4,
"get_nft_serial",
)
});
// ########################################
// Step #2: Test set_data edge cases
// ########################################
check_result(
unsafe { host_bindings_loose::get_ledger_sqn(-1, 4) },
error_codes::INVALID_PARAMS,
"get_ledger_sqn_neg_ptr",
);
with_buffer::<4, _, _>(|ptr, _len| {
check_result(
unsafe { host_bindings_loose::get_ledger_sqn(ptr as i32, -1) },
error_codes::INVALID_PARAMS,
"get_ledger_sqn_neg_len",
)
});
with_buffer::<3, _, _>(|ptr, len| {
check_result(
unsafe { host_bindings_loose::get_ledger_sqn(ptr as i32, len as i32) },
error_codes::BUFFER_TOO_SMALL,
"get_ledger_sqn_buf_too_small",
)
});
with_buffer::<4, _, _>(|ptr, _len| {
check_result(
unsafe { host_bindings_loose::get_ledger_sqn(ptr as i32, 1_000_000_000) },
error_codes::POINTER_OUT_OF_BOUNDS,
"get_ledger_sqn_len_too_long",
)
});
// ########################################
// Step #3: Test getData[Type] edge cases
// ########################################
// SField
check_result(
unsafe { host::get_tx_array_len(2) }, // not a valid SField value
error_codes::INVALID_FIELD,
"get_tx_array_len_invalid_sfield",
);
// Slice
check_result(
unsafe { host_bindings_loose::get_tx_nested_array_len(-1, locator.len() as i32) },
error_codes::INVALID_PARAMS,
"get_tx_nested_array_len_neg_ptr",
);
check_result(
unsafe { host_bindings_loose::get_tx_nested_array_len(locator.as_ptr() as i32, -1) },
error_codes::INVALID_PARAMS,
"get_tx_nested_array_len_neg_len",
);
let long_len = 4 * 1024 + 1;
check_result(
unsafe {
host_bindings_loose::get_tx_nested_array_len(locator.as_ptr() as i32, long_len as i32)
},
error_codes::DATA_FIELD_TOO_LARGE,
"get_tx_nested_array_len_too_long",
);
check_result(
unsafe {
host_bindings_loose::get_tx_nested_array_len(
locator.as_ptr() as i32 + 1_000_000_000,
locator.len() as i32,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"get_tx_nested_array_len_ptr_oob",
);
// uint256
check_result(
unsafe {
host_bindings_loose::cache_ledger_obj(
locator.as_ptr() as i32 + 1_000_000_000,
locator.len() as i32,
1,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"cache_ledger_obj_ptr_oob",
);
check_result(
unsafe {
host_bindings_loose::cache_ledger_obj(locator.as_ptr() as i32, locator.len() as i32, 1)
},
error_codes::INVALID_PARAMS,
"cache_ledger_obj_wrong_len",
);
// AccountID
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe {
host_bindings_loose::account_keylet(
locator.as_ptr() as i32 + 1_000_000_000,
locator.len() as i32,
ptr,
len,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"account_keylet_len_too_long",
)
});
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe {
host_bindings_loose::account_keylet(
locator.as_ptr() as i32,
locator.len() as i32,
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"account_keylet_wrong_len",
)
});
// Currency
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe {
host_bindings_loose::line_keylet(
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,
"line_keylet_len_too_long_currency",
)
});
with_buffer::<32, _, _>(|ptr, len| {
check_result(
unsafe {
host_bindings_loose::line_keylet(
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,
"line_keylet_wrong_len_currency",
)
});
// string
check_result(
unsafe {
host_bindings_loose::trace_num(
locator.as_ptr() as i32 + 1_000_000_000,
locator.len() as i32,
42,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"trace_num_wrong_len_str",
);
// ########################################
// Step #4: Test other host function edge cases
// ########################################
// invalid SFields
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_tx_field(2, ptr, len) },
error_codes::INVALID_FIELD,
"get_tx_field_invalid_sfield",
);
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_current_ledger_obj_field(2, ptr, len) },
error_codes::INVALID_FIELD,
"get_current_ledger_obj_field_invalid_sfield",
);
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_obj_field(1, 2, ptr, len) },
error_codes::INVALID_FIELD,
"get_ledger_obj_field_invalid_sfield",
);
});
check_result(
unsafe { host::get_tx_array_len(2) },
error_codes::INVALID_FIELD,
"get_tx_array_len_invalid_sfield",
);
check_result(
unsafe { host::get_current_ledger_obj_array_len(2) },
error_codes::INVALID_FIELD,
"get_current_ledger_obj_array_len_invalid_sfield",
);
check_result(
unsafe { host::get_ledger_obj_array_len(1, 2) },
error_codes::INVALID_FIELD,
"get_ledger_obj_array_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",
);
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_tx_nested_field(locator.as_ptr(), long_len, ptr, len) },
error_codes::DATA_FIELD_TOO_LARGE,
"get_tx_nested_field_too_big_slice",
);
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::get_current_ledger_obj_nested_field(locator.as_ptr(), long_len, ptr, len)
},
error_codes::DATA_FIELD_TOO_LARGE,
"get_current_ledger_obj_nested_field_too_big_slice",
);
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_ledger_obj_nested_field(1, locator.as_ptr(), long_len, ptr, len) },
error_codes::DATA_FIELD_TOO_LARGE,
"get_ledger_obj_nested_field_too_big_slice",
);
});
check_result(
unsafe { host::get_tx_nested_array_len(locator.as_ptr(), long_len) },
error_codes::DATA_FIELD_TOO_LARGE,
"get_tx_nested_array_len_too_big_slice",
);
check_result(
unsafe { host::get_current_ledger_obj_nested_array_len(locator.as_ptr(), long_len) },
error_codes::DATA_FIELD_TOO_LARGE,
"get_current_ledger_obj_nested_array_len_too_big_slice",
);
check_result(
unsafe { host::get_ledger_obj_nested_array_len(1, locator.as_ptr(), long_len) },
error_codes::DATA_FIELD_TOO_LARGE,
"get_ledger_obj_nested_array_len_too_big_slice",
);
check_result(
unsafe { host::update_data(locator.as_ptr(), long_len) },
error_codes::DATA_FIELD_TOO_LARGE,
"update_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::compute_sha512_half(locator.as_ptr(), long_len, ptr, len) },
error_codes::DATA_FIELD_TOO_LARGE,
"compute_sha512_half_too_big_slice",
);
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::credential_keylet(
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_keylet_too_big_slice",
)
});
check_result(
unsafe {
host::trace(
locator.as_ptr(),
locator.len(),
locator.as_ptr().wrapping_add(1_000_000_000),
locator.len(),
0,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"trace_oob_slice",
);
// invalid UInt256
check_result(
unsafe { host::cache_ledger_obj(locator.as_ptr(), locator.len(), 0) },
error_codes::INVALID_PARAMS,
"cache_ledger_obj_wrong_size_uint256",
);
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::get_nft(
account.0.as_ptr(),
account.0.len(),
locator.as_ptr(),
locator.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"get_nft_wrong_size_uint256",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_issuer(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"get_nft_issuer_wrong_size_uint256",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_taxon(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"get_nft_taxon_wrong_size_uint256",
)
});
check_result(
unsafe { host::get_nft_flags(locator.as_ptr(), locator.len()) },
error_codes::INVALID_PARAMS,
"get_nft_flags_wrong_size_uint256",
);
check_result(
unsafe { host::get_nft_transfer_fee(locator.as_ptr(), locator.len()) },
error_codes::INVALID_PARAMS,
"get_nft_transfer_fee_wrong_size_uint256",
);
with_buffer::<4, _, _>(|ptr, len| {
check_result(
unsafe { host::get_nft_serial(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"get_nft_serial_wrong_size_uint256",
)
});
// invalid AccountID
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::account_keylet(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"account_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::check_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"check_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::credential_keylet(
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_keylet_wrong_size_accountid1",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::credential_keylet(
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_keylet_wrong_size_accountid2",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::delegate_keylet(
locator.as_ptr(), // invalid AccountID size
locator.len(),
account.0.as_ptr(),
account.0.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"delegate_keylet_wrong_size_accountid1",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::delegate_keylet(
account.0.as_ptr(),
account.0.len(),
locator.as_ptr(), // invalid AccountID size
locator.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"delegate_keylet_wrong_size_accountid2",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::deposit_preauth_keylet(
locator.as_ptr(), // invalid AccountID size
locator.len(),
account.0.as_ptr(),
account.0.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"deposit_preauth_keylet_wrong_size_accountid1",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::deposit_preauth_keylet(
account.0.as_ptr(),
account.0.len(),
locator.as_ptr(), // invalid AccountID size
locator.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"deposit_preauth_keylet_wrong_size_accountid2",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::did_keylet(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"did_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::escrow_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"escrow_keylet_wrong_size_accountid",
)
});
let currency: &[u8] = b"USD00000000000000000"; // 20 bytes
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::line_keylet(
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,
"line_keylet_wrong_size_accountid1",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::line_keylet(
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,
"line_keylet_wrong_size_accountid2",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::nft_offer_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"nft_offer_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::offer_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"offer_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::oracle_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"oracle_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::paychan_keylet(
locator.as_ptr(), // invalid AccountID size
locator.len(),
account.0.as_ptr(),
account.0.len(),
1,
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"paychan_keylet_wrong_size_accountid1",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::paychan_keylet(
account.0.as_ptr(),
account.0.len(),
locator.as_ptr(), // invalid AccountID size
locator.len(),
1,
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"paychan_keylet_wrong_size_accountid2",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::signers_keylet(locator.as_ptr(), locator.len(), ptr, len) },
error_codes::INVALID_PARAMS,
"signers_keylet_wrong_size_accountid",
)
});
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe { host::ticket_keylet(locator.as_ptr(), locator.len(), 1, ptr, len) },
error_codes::INVALID_PARAMS,
"ticket_keylet_wrong_size_accountid",
)
});
let uint256: &[u8] = b"00000000000000000000000000000001";
with_buffer::<2, _, _>(|ptr, len| {
check_result(
unsafe {
host::get_nft(
locator.as_ptr(),
locator.len(),
uint256.as_ptr(),
uint256.len(),
ptr,
len,
)
},
error_codes::INVALID_PARAMS,
"get_nft_wrong_size_accountid",
)
});
// invalid Currency was already tested above
// invalid string
check_result(
unsafe {
host::trace(
locator.as_ptr().wrapping_add(1_000_000_000),
locator.len(),
uint256.as_ptr(),
uint256.len(),
0,
)
},
error_codes::POINTER_OUT_OF_BOUNDS,
"get_nft_wrong_size_string",
);
// trace too large
check_result(
unsafe {
host::trace(
locator.as_ptr(),
locator.len(),
locator.as_ptr(),
long_len,
0,
)
},
error_codes::DATA_FIELD_TOO_LARGE,
"trace_too_long",
);
check_result(
unsafe { host::trace_num(locator.as_ptr(), long_len, 1) },
error_codes::DATA_FIELD_TOO_LARGE,
"trace_num_too_long",
);
1 // <-- If we get here, finish the escrow.
}

View File

@@ -0,0 +1,130 @@
import os
import sys
import subprocess
import re
OPT = "-Oz"
def update_fixture(project_name, wasm):
fixture_name = (
re.sub(r"_([a-z])", lambda m: m.group(1).upper(), project_name) + "WasmHex"
)
print(f"Updating fixture: {fixture_name}")
cpp_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fixtures.cpp"))
h_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "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\n extern 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 process_rust(project_name):
project_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), project_name)
)
wasm_location = f"target/wasm32-unknown-unknown/release/{project_name}.wasm"
build_cmd = (
f"(cd {project_path} "
f"&& cargo build --target wasm32-unknown-unknown --release "
f"&& wasm-opt {wasm_location} {OPT} -o {wasm_location}"
")"
)
try:
result = subprocess.run(
build_cmd, shell=True, check=True, capture_output=True, text=True
)
print(f"stdout: {result.stdout}")
if result.stderr:
print(f"stderr: {result.stderr}")
print(f"WASM file for {project_name} has been built and optimized.")
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
src_path = os.path.abspath(
os.path.join(
os.path.dirname(__file__),
f"{project_name}/target/wasm32-unknown-unknown/release/{project_name}.wasm",
)
)
with open(src_path, "rb") as f:
data = f.read()
wasm = data.hex()
update_fixture(project_name, wasm)
def process_c(project_name):
project_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), f"{project_name}.c")
)
wasm_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), f"{project_name}.wasm")
)
build_cmd = (
f"$CC --sysroot=$SYSROOT -I$SYSROOT/include/wasm32-wasi "
f"-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 "
f"-o {wasm_path} {project_path}"
f"&& wasm-opt {wasm_path} {OPT} -o {wasm_path}"
)
try:
result = subprocess.run(
build_cmd, shell=True, check=True, capture_output=True, text=True
)
print(f"stdout: {result.stdout}")
if result.stderr:
print(f"stderr: {result.stderr}")
print(
f"WASM file for {project_name} has been built with WASI support using clang."
)
except subprocess.CalledProcessError as e:
print(f"exec error: {e}")
sys.exit(1)
with open(wasm_path, "rb") as f:
data = f.read()
wasm = data.hex()
update_fixture(project_name, wasm)
if __name__ == "__main__":
if len(sys.argv) > 2:
print("Usage: python copyFixtures.py [<project_name>]")
sys.exit(1)
if len(sys.argv) == 2:
process_rust(sys.argv[1])
else:
dirs = [
d
for d in os.listdir(os.path.dirname(__file__))
if os.path.isdir(os.path.join(os.path.dirname(__file__), d))
]
c_files = [f for f in os.listdir(os.path.dirname(__file__)) if f.endswith(".c")]
for d in dirs:
process_rust(d)
for c in c_files:
process_c(c[:-2])
print("All fixtures have been processed.")

View File

@@ -0,0 +1,34 @@
(module
(type (;0;) (func))
(type (;1;) (func (result i32)))
(func (;0;) (type 0))
(func (;1;) (type 1) (result i32)
f32.const -2048
f32.const 2050
f32.sub
drop
i32.const 1)
(memory (;0;) 2)
(global (;0;) i32 (i32.const 1024))
(global (;1;) i32 (i32.const 1024))
(global (;2;) i32 (i32.const 2048))
(global (;3;) i32 (i32.const 2048))
(global (;4;) i32 (i32.const 67584))
(global (;5;) i32 (i32.const 1024))
(global (;6;) i32 (i32.const 67584))
(global (;7;) i32 (i32.const 131072))
(global (;8;) i32 (i32.const 0))
(global (;9;) i32 (i32.const 1))
(export "memory" (memory 0))
(export "__wasm_call_ctors" (func 0))
(export "finish" (func 1))
(export "buf" (global 0))
(export "__dso_handle" (global 1))
(export "__data_end" (global 2))
(export "__stack_low" (global 3))
(export "__stack_high" (global 4))
(export "__global_base" (global 5))
(export "__heap_base" (global 6))
(export "__heap_end" (global 7))
(export "__memory_base" (global 8))
(export "__table_base" (global 9)))

View File

@@ -0,0 +1,12 @@
// typedef long long mint;
typedef int mint;
mint
fib(mint n)
{
if (!n)
return 0;
if (n <= 2)
return 1;
return fib(n - 1) + fib(n - 2);
}

File diff suppressed because it is too large Load Diff

View File

@@ -23,45 +23,29 @@
#include <string>
extern std::string const ledgerSqnHex;
extern std::string const ledgerSqnWasmHex;
extern std::string const allHostFunctionsHex;
extern std::string const allHostFunctionsWasmHex;
extern std::string const deepRecursionHex;
extern std::string const tx_js;
extern std::string const fibWasmHex;
extern std::string const lo_js;
extern std::string const b58WasmHex;
extern std::string const lo_js2;
extern std::string const sha512PureWasmHex;
extern std::string const fib32Hex;
extern std::string const zkProofWasmHex;
extern std::string const fib64Hex;
extern std::string const b58Hex;
extern std::string const sha512PureHex;
extern std::string const checkJsonHex;
extern std::string const compareJsonHex;
extern std::string const zkProofHex;
extern std::string const sp1_wasm;
extern std::string const reqNonexistentField;
extern std::string const sp1WasmHex;
extern std::string const hfPerfTest;
extern std::string const opcCallPerfTest;
extern std::string const allKeyletsWasmHex;
extern std::string const keyletHostFunctions;
extern std::string const codecovTestsWasmHex;
extern std::string const codecovWasm;
extern std::string const floatHex;
extern std::string const floatTestsWasmHex;
extern std::string const float0Hex;

View File

@@ -0,0 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "float_tests"
version = "0.0.1"
dependencies = [
"xrpl-std",
]
[[package]]
name = "xrpl-std"
version = "0.0.1"
source = "git+https://github.com/ripple/craft.git?branch=main#94fb247e0c21b9e7fecb91ce71ef7f74ef4a7931"

View File

@@ -0,0 +1,21 @@
[package]
name = "float_tests"
version = "0.0.1"
edition = "2024"
# 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/craft.git", branch = "main", package = "xrpl-std" }
[profile.dev]
panic = "abort"

View File

@@ -0,0 +1,460 @@
#![allow(unused_imports)]
#![allow(unused_variables)]
#![cfg_attr(target_arch = "wasm32", no_std)]
#[cfg(not(target_arch = "wasm32"))]
extern crate std;
use xrpl_std::core::locator::Locator;
use xrpl_std::decode_hex_32;
use xrpl_std::host::trace::DataRepr::AsHex;
use xrpl_std::host::trace::{trace, trace_data, trace_float, trace_num, DataRepr};
use xrpl_std::host::{
cache_ledger_obj, float_add, float_compare, float_divide, float_from_int, float_from_uint,
float_log, float_multiply, float_pow, float_root, float_set, float_subtract,
get_ledger_obj_array_len, get_ledger_obj_field, get_ledger_obj_nested_field,
trace_opaque_float, FLOAT_NEGATIVE_ONE, FLOAT_ONE, FLOAT_ROUNDING_MODES_TO_NEAREST,
};
use xrpl_std::sfield;
use xrpl_std::sfield::{
Account, AccountTxnID, Balance, Domain, EmailHash, Flags, LedgerEntryType, MessageKey,
OwnerCount, PreviousTxnID, PreviousTxnLgrSeq, RegularKey, Sequence, TicketCount, TransferRate,
};
fn test_float_from_wasm() {
let _ = trace("\n$$$ test_float_from_wasm $$$");
let mut f: [u8; 8] = [0u8; 8];
if 8 == unsafe { float_from_int(12300, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace_float(" float from i64 12300:", &f);
let _ = trace_data(" float from i64 12300 as HEX:", &f, AsHex);
} else {
let _ = trace(" float from i64 12300: failed");
}
let u64_value: u64 = 12300;
if 8 == unsafe {
float_from_uint(
&u64_value as *const u64 as *const u8,
8,
f.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
} {
let _ = trace_float(" float from u64 12300:", &f);
} else {
let _ = trace(" float from u64 12300: failed");
}
if 8 == unsafe { float_set(2, 123, f.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace_float(" float from exp 2, mantissa 123:", &f);
} else {
let _ = trace(" float from exp 2, mantissa 3: failed");
}
let _ = trace_float(" float from const 1:", &FLOAT_ONE);
let _ = trace_float(" float from const -1:", &FLOAT_NEGATIVE_ONE);
}
fn test_float_compare() {
let _ = trace("\n$$$ test_float_compare $$$");
let mut f1: [u8; 8] = [0u8; 8];
if 8 != unsafe { float_from_int(1, f1.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
let _ = trace(" float from 1: failed");
} else {
let _ = trace_float(" float from 1:", &f1);
}
if 0 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_ONE.as_ptr(), 8) } {
let _ = trace(" float from 1 == FLOAT_ONE");
} else {
let _ = trace(" float from 1 != FLOAT_ONE");
}
if 1 == unsafe { float_compare(f1.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
let _ = trace(" float from 1 > FLOAT_NEGATIVE_ONE");
} else {
let _ = trace(" float from 1 !> FLOAT_NEGATIVE_ONE");
}
if 2 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f1.as_ptr(), 8) } {
let _ = trace(" FLOAT_NEGATIVE_ONE < float from 1");
} else {
let _ = trace(" FLOAT_NEGATIVE_ONE !< float from 1");
}
}
fn test_float_add_subtract() {
let _ = trace("\n$$$ test_float_add_subtract $$$");
let mut f_compute: [u8; 8] = FLOAT_ONE;
for i in 0..9 {
unsafe {
float_add(
f_compute.as_ptr(),
8,
FLOAT_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
}
let mut f10: [u8; 8] = [0u8; 8];
if 8 != unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) } {
// let _ = trace(" float from 10: failed");
}
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" repeated add: good");
} else {
let _ = trace(" repeated add: bad");
}
for i in 0..11 {
unsafe {
float_subtract(
f_compute.as_ptr(),
8,
FLOAT_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
}
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, FLOAT_NEGATIVE_ONE.as_ptr(), 8) } {
let _ = trace(" repeated subtract: good");
} else {
let _ = trace(" repeated subtract: bad");
}
}
fn test_float_multiply_divide() {
let _ = trace("\n$$$ test_float_multiply_divide $$$");
let mut f10: [u8; 8] = [0u8; 8];
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
let mut f_compute: [u8; 8] = FLOAT_ONE;
for i in 0..6 {
unsafe {
float_multiply(
f_compute.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
}
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
if 0 == unsafe { float_compare(f1000000.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" repeated multiply: good");
} else {
let _ = trace(" repeated multiply: bad");
}
for i in 0..7 {
unsafe {
float_divide(
f_compute.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
}
let mut f01: [u8; 8] = [0u8; 8];
unsafe { float_set(-1, 1, f01.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
if 0 == unsafe { float_compare(f_compute.as_ptr(), 8, f01.as_ptr(), 8) } {
let _ = trace(" repeated divide: good");
} else {
let _ = trace(" repeated divide: bad");
}
}
fn test_float_pow() {
let _ = trace("\n$$$ test_float_pow $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_pow(
FLOAT_ONE.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cube of 1:", &f_compute);
unsafe {
float_pow(
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
6,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 6th power of -1:", &f_compute);
let mut f9: [u8; 8] = [0u8; 8];
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_pow(
f9.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float square of 9:", &f_compute);
unsafe {
float_pow(
f9.as_ptr(),
8,
0,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 0th power of 9:", &f_compute);
let mut f0: [u8; 8] = [0u8; 8];
unsafe { float_from_int(0, f0.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_pow(
f0.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float square of 0:", &f_compute);
let r = unsafe {
float_pow(
f0.as_ptr(),
8,
0,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_num(
" float 0th power of 0 (expecting INVALID_PARAMS error):",
r as i64,
);
}
fn test_float_root() {
let _ = trace("\n$$$ test_float_root $$$");
let mut f9: [u8; 8] = [0u8; 8];
unsafe { float_from_int(9, f9.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_root(
f9.as_ptr(),
8,
2,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float sqrt of 9:", &f_compute);
unsafe {
float_root(
f9.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cbrt of 9:", &f_compute);
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
unsafe {
float_root(
f1000000.as_ptr(),
8,
3,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float cbrt of 1000000:", &f_compute);
unsafe {
float_root(
f1000000.as_ptr(),
8,
6,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" float 6th root of 1000000:", &f_compute);
}
fn test_float_log() {
let _ = trace("\n$$$ test_float_log $$$");
let mut f1000000: [u8; 8] = [0u8; 8];
unsafe {
float_from_int(
1000000,
f1000000.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_log(
f1000000.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" log_10 of 1000000:", &f_compute);
}
fn test_float_negate() {
let _ = trace("\n$$$ test_float_negate $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
unsafe {
float_multiply(
FLOAT_ONE.as_ptr(),
8,
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
if 0 == unsafe { float_compare(FLOAT_NEGATIVE_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" negate const 1: good");
} else {
let _ = trace(" negate const 1: bad");
}
unsafe {
float_multiply(
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
FLOAT_NEGATIVE_ONE.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
// let _ = trace_float(" float:", &f_compute);
if 0 == unsafe { float_compare(FLOAT_ONE.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" negate const -1: good");
} else {
let _ = trace(" negate const -1: bad");
}
}
fn test_float_invert() {
let _ = trace("\n$$$ test_float_invert $$$");
let mut f_compute: [u8; 8] = [0u8; 8];
let mut f10: [u8; 8] = [0u8; 8];
unsafe { float_from_int(10, f10.as_mut_ptr(), 8, FLOAT_ROUNDING_MODES_TO_NEAREST) };
unsafe {
float_divide(
FLOAT_ONE.as_ptr(),
8,
f10.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" invert a float from 10:", &f_compute);
unsafe {
float_divide(
FLOAT_ONE.as_ptr(),
8,
f_compute.as_ptr(),
8,
f_compute.as_mut_ptr(),
8,
FLOAT_ROUNDING_MODES_TO_NEAREST,
)
};
let _ = trace_float(" invert again:", &f_compute);
// if f10's value is 7, then invert twice won't match the original value
if 0 == unsafe { float_compare(f10.as_ptr(), 8, f_compute.as_ptr(), 8) } {
let _ = trace(" invert twice: good");
} else {
let _ = trace(" invert twice: bad");
}
}
#[unsafe(no_mangle)]
pub extern "C" fn finish() -> i32 {
test_float_from_wasm();
test_float_compare();
test_float_add_subtract();
test_float_multiply_divide();
test_float_pow();
test_float_root();
test_float_log();
test_float_negate();
test_float_invert();
1
}

View File

@@ -0,0 +1,27 @@
#include <stdint.h>
int32_t
get_ledger_sqn(uint8_t*, int32_t);
// int32_t trace(uint8_t const*, int32_t, uint8_t const*, int32_t, int32_t);
// int32_t trace_num(uint8_t const*, int32_t, int64_t);
uint8_t buf[1024];
// char const test_res[] = "sqn: ";
// char const test_name[] = "TEST get_ledger_sqn";
int
finish()
{
// trace((uint8_t const *)test_name, sizeof(test_name) - 1, 0, 0, 0);
// memset(buf, 0, sizeof(buf));
// for(int i = 0; i < sizeof(buf); ++i) buf[i] = 0;
int x = get_ledger_sqn(buf, sizeof(int32_t));
if (x >= 0)
x = *((int32_t*)buf);
// trace_num((uint8_t const *)test_res, sizeof(test_res) - 1, x);
return x < 0 ? x : (x >= 5 ? 1 : 0);
}

View File

@@ -0,0 +1,145 @@
#include <stdint.h>
#include <stdlib.h>
static uint64_t const K512[] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
#define ROTATE(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Sigma0(x) (ROTATE((x), 28) ^ ROTATE((x), 34) ^ ROTATE((x), 39))
#define Sigma1(x) (ROTATE((x), 14) ^ ROTATE((x), 18) ^ ROTATE((x), 41))
#define sigma0(x) (ROTATE((x), 1) ^ ROTATE((x), 8) ^ ((x) >> 7))
#define sigma1(x) (ROTATE((x), 19) ^ ROTATE((x), 61) ^ ((x) >> 6))
#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
static inline uint64_t
B2U64(uint8_t val, uint8_t sh)
{
return ((uint64_t)val) << sh;
}
void*
allocate(int sz)
{
return malloc(sz);
}
void
deallocate(void* p)
{
free(p);
}
uint8_t e_data[32 * 1024];
uint8_t*
sha512_process(uint8_t const* data, int32_t length)
{
static uint64_t state[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint64_t a, b, c, d, e, f, g, h, s0, s1, T1, T2;
uint64_t X[16];
uint64_t blocks = length / 128;
while (blocks--)
{
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
unsigned i;
for (i = 0; i < 16; i++)
{
X[i] = B2U64(data[0], 56) | B2U64(data[1], 48) |
B2U64(data[2], 40) | B2U64(data[3], 32) | B2U64(data[4], 24) |
B2U64(data[5], 16) | B2U64(data[6], 8) | B2U64(data[7], 0);
data += 8;
T1 = h;
T1 += Sigma1(e);
T1 += Ch(e, f, g);
T1 += K512[i];
T1 += X[i];
T2 = Sigma0(a);
T2 += Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
for (i = 16; i < 80; i++)
{
s0 = X[(i + 1) & 0x0f];
s0 = sigma0(s0);
s1 = X[(i + 14) & 0x0f];
s1 = sigma1(s1);
T1 = X[i & 0xf] += s0 + s1 + X[(i + 9) & 0xf];
T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i];
T2 = Sigma0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
}
return (uint8_t*)(state);
}
// int main ()
//{
// return 0;
// }

1384
src/test/app/wasm_fixtures/sp1/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
[package]
edition = "2021"
name = "sp1"
version = "0.0.1"
[lib]
crate-type = ["cdylib"]
[dependencies]
sp1-verifier = "4.1.3"
[profile.release]
opt-level = 3 # "z" for size or "3" for speed
lto = true # Link Time Optimization
codegen-units = 1 # Single unit = better optimization
panic = "abort" # Smaller binary, faster execution

View File

@@ -0,0 +1,37 @@
use sp1_verifier::Groth16Verifier;
#[no_mangle]
pub fn sp1_groth16_verifier() -> bool {
let groth16_vk = *sp1_verifier::GROTH16_VK_BYTES;
let proof: Vec<u8> = vec![
17, 182, 160, 157, 31, 189, 116, 200, 17, 224, 230, 34, 195, 108, 230, 185, 62, 91, 181,
212, 80, 111, 197, 89, 247, 206, 99, 206, 147, 13, 216, 101, 252, 192, 149, 2, 40, 4, 249,
44, 97, 227, 127, 36, 244, 18, 27, 75, 248, 3, 45, 11, 103, 45, 183, 204, 61, 217, 19, 208,
66, 73, 202, 108, 136, 162, 221, 184, 6, 189, 49, 196, 104, 128, 151, 21, 104, 109, 145,
150, 243, 51, 27, 243, 203, 75, 176, 59, 193, 51, 177, 64, 83, 13, 133, 140, 248, 242, 13,
24, 12, 103, 126, 112, 244, 181, 129, 246, 52, 110, 134, 57, 149, 23, 163, 43, 202, 7, 164,
233, 179, 160, 16, 5, 22, 45, 129, 76, 183, 76, 150, 139, 27, 224, 191, 59, 47, 105, 71,
47, 8, 176, 157, 159, 234, 253, 239, 131, 138, 120, 101, 4, 98, 236, 106, 235, 98, 76, 93,
220, 174, 153, 58, 216, 28, 141, 129, 191, 188, 40, 184, 225, 22, 61, 75, 139, 159, 162,
117, 83, 214, 239, 1, 246, 236, 255, 64, 228, 116, 107, 206, 23, 59, 3, 221, 95, 14, 170,
28, 171, 36, 179, 75, 101, 177, 40, 198, 12, 193, 82, 105, 155, 177, 62, 158, 72, 209, 252,
51, 169, 109, 32, 121, 179, 194, 73, 164, 14, 8, 206, 181, 9, 5, 38, 74, 136, 97, 0, 89,
80, 75, 88, 228, 94, 46, 196, 199, 83, 229, 11, 103, 115, 25, 31, 215, 137, 65, 159, 95,
192,
];
let sp1_public_values = vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 8,
];
let sp1_vkey_hash: String =
"0x00aea8e9c83c73d74036923de1b4a66d18547d58eee4eacfee70235ed291954c".to_string();
let _ = Groth16Verifier::verify(&proof, &sp1_public_values, &sp1_vkey_hash, groth16_vk);
true
}

View File

@@ -0,0 +1,106 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "bls12_381"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403"
dependencies = [
"ff",
"group",
"pairing",
"rand_core",
"subtle",
]
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"bitvec",
"rand_core",
"subtle",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "pairing"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f"
dependencies = [
"group",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "zk_proof"
version = "0.0.1"
dependencies = [
"bls12_381",
"group",
]

View File

@@ -0,0 +1,19 @@
[package]
edition = "2021"
name = "zk_proof"
version = "0.0.1"
[lib]
crate-type = ["cdylib"]
[dependencies]
# bellman = "=0.14.0"
bls12_381 = "=0.8.0"
group = "0.13.0"
[profile.release]
# opt-level = 3 # Optimize for time
opt-level = "z" # Optimize for size
lto = true # Enable Link Time Optimization
codegen-units = 1
panic = "abort" # Remove unnecessary panic machinery

View File

@@ -0,0 +1,254 @@
use bls12_381::multi_miller_loop;
use bls12_381::Scalar;
use bls12_381::{G1Affine, G2Affine, G2Prepared};
use group::prime::PrimeCurveAffine;
use group::Curve;
use std::mem;
use std::os::raw::c_void;
// use std::time::{Instant};
// Groth16 proof struct
pub struct Proof {
pub a: G1Affine,
pub b: G2Affine,
pub c: G1Affine,
}
// Groth16 verification key struct
pub struct VerifyingKey {
pub alpha_g1: G1Affine,
pub beta_g1: G1Affine,
pub beta_g2: G2Affine,
pub gamma_g2: G2Affine,
pub delta_g1: G1Affine,
pub delta_g2: G2Affine,
pub ic: Vec<G1Affine>,
}
#[no_mangle]
pub extern "C" fn allocate(size: usize) -> *mut c_void {
let mut buffer = Vec::with_capacity(size);
let pointer = buffer.as_mut_ptr();
mem::forget(buffer);
pointer as *mut c_void
// }
}
#[no_mangle]
fn deserialize_g1_wasm(buffer: &mut Vec<u8>) -> G1Affine {
let d_g1 = G1Affine::from_compressed(&buffer[0..48].try_into().unwrap())
.expect("Failed to deserialize vk");
d_g1
}
fn deserialize_g2_wasm(buffer: &mut Vec<u8>) -> G2Affine {
let d_g2 = G2Affine::from_compressed(&buffer[0..96].try_into().unwrap())
.expect("Failed to deserialize vk");
d_g2
}
#[no_mangle]
// pub extern fn bellman_groth16_test(pointer: *mut u8, capacity: usize) -> bool {
pub extern "C" fn bellman_groth16_test() -> bool {
// let mut bytes = Vec::new();
// unsafe {
// // println!("Test in vm {:?}", pointer);
// let v = Vec::from_raw_parts(pointer, capacity, capacity); //TODO no need to deallocate??
// bytes.extend_from_slice(&v);
// }
// Hardcode the input bytes for testing in different WASM VMs
// let bytes = [172, 197, 81, 189, 121, 193, 159, 27, 92, 95, 151, 164, 40, 59, 214, 96, 132, 58, 87, 37, 169, 1, 63, 230, 35, 74, 245, 6, 185, 56, 120, 108, 214, 179, 187, 21, 36, 206, 43, 160, 10, 250, 249, 73, 210, 35, 137, 87, 177, 66, 65, 154, 11, 232, 137, 246, 125, 72, 227, 222, 116, 168, 87, 24, 165, 160, 132, 109, 108, 101, 222, 143, 78, 97, 48, 95, 59, 177, 29, 247, 219, 166, 73, 249, 69, 206, 15, 151, 30, 248, 235, 63, 148, 240, 17, 22, 150, 67, 252, 141, 95, 179, 94, 111, 207, 201, 192, 144, 154, 94, 21, 2, 22, 58, 96, 144, 227, 107, 107, 182, 142, 0, 57, 27, 168, 39, 226, 40, 163, 159, 112, 83, 196, 182, 215, 74, 92, 20, 158, 60, 23, 184, 198, 143, 17, 6, 242, 7, 75, 220, 87, 47, 224, 145, 99, 169, 203, 218, 112, 185, 51, 102, 59, 56, 171, 46, 49, 255, 116, 108, 241, 50, 180, 247, 62, 218, 181, 197, 155, 80, 61, 252, 8, 41, 232, 73, 51, 250, 223, 82, 94, 8, 185, 83, 223, 187, 6, 41, 20, 62, 189, 254, 11, 11, 58, 187, 200, 88, 53, 234, 98, 172, 213, 62, 22, 34, 90, 166, 182, 133, 8, 230, 103, 219, 233, 141, 10, 137, 210, 151, 4, 129, 29, 92, 103, 251, 72, 182, 162, 59, 20, 222, 188, 232, 13, 74, 214, 182, 172, 120, 33, 198, 57, 204, 134, 93, 26, 79, 213, 45, 146, 6, 128, 103, 63, 202, 226, 120, 141, 193, 248, 65, 196, 235, 21, 184, 104, 228, 206, 117, 190, 28, 153, 183, 68, 36, 63, 60, 131, 87, 137, 213, 105, 27, 110, 37, 238, 200, 250, 145, 76, 25, 57, 81, 69, 164, 208, 255, 49, 80, 14, 64, 181, 143, 12, 58, 35, 63, 199, 35, 70, 25, 86, 158, 210, 150, 59, 159, 253, 238, 174, 211, 142, 166, 223, 51, 134, 118, 171, 27, 218, 219, 117, 163, 71, 134, 95, 142, 83, 251, 240, 241, 162, 232, 93, 248, 167, 112, 197, 212, 169, 209, 159, 101, 140, 248, 222, 234, 201, 169, 76, 242, 7, 10, 192, 30, 151, 167, 74, 186, 97, 121, 144, 36, 6, 187, 92, 7, 248, 45, 134, 85, 240, 112, 74, 224, 70, 64, 198, 59, 26, 195, 192, 140, 101, 118, 175, 17, 160, 195, 142, 133, 1, 139, 5, 130, 245, 17, 73, 176, 232, 107, 130, 172, 110, 20, 190, 37, 108, 250, 178, 187, 151, 158, 35, 248, 246, 143, 38, 212, 133, 226, 24, 45, 33, 164, 46, 125, 200, 157, 253, 225, 132, 181, 60, 90, 7, 240, 80, 232, 97, 206, 164, 28, 12, 75, 68, 126, 230, 145, 216, 45, 180, 203, 19, 152, 29, 203, 9, 4, 145, 122, 206, 146, 179, 44, 145, 191, 126, 199, 175, 171, 127, 189, 222, 108, 126, 161, 80, 190, 47, 44, 8, 40, 65, 68, 95, 61, 109, 148, 175, 113, 226, 8, 93, 126, 53, 39, 192, 196, 6, 152, 194, 105, 169, 226, 192, 201, 184, 198, 134, 210, 153, 170, 12, 241, 90, 250, 233, 20, 152, 119, 142, 120, 83, 2, 164, 80, 178, 125, 227, 253, 207, 240, 201, 127, 213, 196, 100, 90, 65, 120, 50, 108, 175, 34, 192, 197, 173, 202, 176, 210, 131, 22, 216, 57, 169, 241, 28, 40, 44, 62, 11, 42, 50, 46, 204, 242, 109, 158, 114, 41, 127, 206, 25, 194, 255, 128, 245, 232, 193, 189, 229, 51, 93, 94, 64, 117, 33, 132, 75, 253, 114, 64, 116, 155, 183, 137, 112, 201, 243, 13, 221, 142, 164, 59, 98, 152, 249, 40, 133, 70, 185, 231, 249, 151, 253, 240, 122, 214, 60, 18, 132, 177, 37, 42, 75, 206, 12, 100, 214, 248, 234, 78, 165, 74, 212, 248, 32, 162, 254, 227, 218, 46, 9, 87, 0, 118, 13, 249, 107, 83, 5, 138, 223, 9, 247, 70, 160, 228, 197, 54, 87, 18, 1, 37, 199, 162, 84, 189, 161, 10, 26, 75, 45, 168, 185, 153, 245, 243, 51, 176, 208, 187, 235, 135, 239, 231, 42, 43, 233, 150, 46, 249, 73, 229, 138, 84, 89, 75, 129, 238, 211, 80, 147, 67, 159, 227, 214, 131, 188, 130, 70, 224, 1, 77, 139, 239, 185, 53, 68, 41, 193, 207, 16, 2, 33, 139, 214, 103, 240, 14, 141, 223, 24, 236, 50, 64, 79, 178, 6, 79, 38, 165, 35, 173, 203, 101, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88, 106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let bytes = [
147, 235, 138, 182, 249, 146, 149, 28, 58, 36, 144, 99, 188, 155, 153, 135, 239, 79, 76,
109, 152, 156, 202, 1, 153, 84, 239, 184, 69, 145, 133, 48, 156, 80, 122, 227, 231, 161,
137, 232, 67, 183, 34, 186, 230, 135, 25, 90, 136, 201, 110, 134, 208, 93, 78, 82, 153,
239, 208, 236, 160, 231, 192, 150, 215, 128, 193, 255, 107, 39, 133, 12, 136, 148, 119, 17,
59, 198, 100, 49, 37, 89, 132, 205, 45, 79, 151, 112, 247, 140, 94, 179, 215, 165, 52, 182,
153, 68, 204, 210, 218, 156, 69, 74, 192, 30, 160, 13, 80, 188, 23, 112, 21, 124, 91, 147,
21, 140, 217, 226, 248, 60, 182, 119, 18, 34, 32, 41, 181, 128, 165, 97, 168, 76, 98, 44,
114, 122, 128, 215, 68, 156, 18, 91, 5, 33, 22, 141, 249, 137, 49, 252, 82, 122, 206, 58,
183, 108, 176, 15, 38, 183, 87, 254, 34, 102, 195, 78, 166, 227, 96, 180, 137, 173, 131,
178, 179, 25, 89, 159, 5, 73, 125, 24, 25, 86, 227, 19, 184, 117, 228, 173, 150, 1, 82,
142, 48, 251, 236, 132, 73, 79, 201, 165, 192, 191, 195, 60, 100, 198, 251, 187, 161, 220,
63, 143, 38, 21, 189, 219, 194, 100, 64, 186, 102, 7, 186, 213, 227, 92, 228, 52, 181, 171,
223, 222, 218, 206, 221, 22, 15, 46, 77, 175, 34, 43, 221, 110, 21, 89, 149, 213, 68, 242,
140, 185, 176, 73, 88, 216, 75, 237, 209, 10, 75, 251, 152, 101, 15, 146, 168, 27, 81, 8,
61, 76, 103, 230, 171, 23, 144, 171, 6, 118, 157, 233, 234, 214, 132, 106, 30, 171, 121,
77, 147, 175, 170, 62, 48, 251, 12, 221, 202, 109, 80, 97, 180, 27, 45, 87, 162, 19, 168,
152, 27, 205, 113, 91, 83, 52, 99, 109, 17, 149, 189, 244, 174, 164, 192, 79, 133, 111,
195, 215, 232, 129, 166, 204, 3, 169, 248, 49, 18, 190, 198, 145, 177, 169, 10, 4, 66, 134,
46, 11, 163, 170, 94, 230, 234, 234, 43, 122, 51, 230, 100, 106, 149, 228, 208, 217, 87,
231, 125, 170, 47, 143, 151, 45, 208, 64, 91, 10, 188, 136, 15, 155, 131, 200, 141, 243,
200, 5, 109, 22, 98, 189, 193, 44, 40, 95, 126, 145, 234, 190, 205, 179, 172, 224, 147,
253, 238, 162, 157, 60, 126, 9, 174, 34, 16, 161, 197, 60, 243, 211, 241, 78, 114, 51, 167,
214, 53, 149, 172, 56, 149, 32, 66, 123, 48, 240, 179, 53, 154, 29, 134, 34, 141, 204, 168,
184, 158, 165, 115, 241, 119, 228, 11, 35, 82, 186, 132, 103, 65, 243, 215, 31, 105, 201,
191, 155, 210, 53, 194, 76, 63, 199, 181, 28, 138, 181, 181, 211, 145, 15, 139, 244, 38,
56, 159, 161, 95, 46, 147, 141, 163, 221, 88, 167, 134, 73, 45, 70, 98, 98, 167, 55, 52,
234, 110, 150, 79, 248, 157, 167, 84, 210, 89, 10, 193, 169, 32, 40, 218, 7, 236, 206, 85,
178, 174, 157, 132, 181, 192, 119, 60, 205, 46, 217, 120, 97, 59, 82, 121, 11, 189, 21,
213, 176, 255, 225, 57, 76, 239, 38, 99, 226, 55, 98, 227, 10, 45, 193, 69, 255, 247, 39,
121, 86, 150, 6, 220, 98, 41, 132, 237, 189, 169, 110, 213, 115, 33, 228, 197, 61, 219,
202, 58, 54, 70, 223, 179, 208, 139, 232, 103, 76, 165, 169, 68, 6, 148, 47, 244, 26, 203,
186, 110, 69, 44, 175, 128, 119, 212, 188, 167, 223, 87, 119, 238, 199, 201, 61, 78, 96,
175, 0, 156, 145, 196, 253, 162, 175, 172, 227, 80, 251, 96, 61, 189, 35, 13, 97, 22, 157,
86, 249, 128, 148, 172, 66, 80, 172, 208, 222, 131, 0, 207, 80, 163, 27, 155, 113, 57, 186,
246, 139, 111, 71, 117, 152, 184, 60, 1, 230, 44, 169, 213, 88, 82, 156, 194, 234, 41, 183,
87, 36, 175, 154, 156, 128, 59, 187, 208, 101, 9, 51, 205, 42, 174, 29, 215, 43, 150, 183,
129, 125, 2, 84, 210, 149, 245, 126, 140, 166, 255, 134, 116, 162, 107, 82, 178, 158, 38,
11, 135, 91, 224, 157, 112, 189, 164, 250, 1, 215, 49, 21, 214, 211, 73, 243, 251, 58, 198,
1, 165, 196, 122, 13, 238, 252, 227, 229, 149, 47, 13, 173, 171, 176, 185, 220, 82, 96,
163, 4, 36, 199, 152, 88, 3, 162, 49, 51, 4, 151, 127, 49, 47, 223, 244, 157, 229, 7, 88,
106, 141, 167, 183, 220, 15, 8, 119, 12, 82, 218, 14, 207, 0, 73, 27, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
// ***** Test deserialization and reconstruction of vk *****
// let start_key_recons = Instant::now();
// println!("Start verification key reconstruction");
// alpha_g1
let mut vec_alpha_g1 = bytes[0..48].to_vec();
let r_alpha_g1 = deserialize_g1_wasm(&mut vec_alpha_g1);
// beta_g1
let mut vec_beta_g1 = bytes[48..96].to_vec();
let r_beta_g1 = deserialize_g1_wasm(&mut vec_beta_g1);
// beta_g2
let mut vec_beta_g2 = bytes[96..192].to_vec();
let r_beta_g2 = deserialize_g2_wasm(&mut vec_beta_g2);
// gamma_g2
let mut vec_gamma_g2 = bytes[192..288].to_vec();
let r_gamma_g2 = deserialize_g2_wasm(&mut vec_gamma_g2);
// delta_g1
let mut vec_delta_g1 = bytes[288..336].to_vec();
let r_delta_g1 = deserialize_g1_wasm(&mut vec_delta_g1);
// delta_g2
let mut vec_delta_g2 = bytes[336..432].to_vec();
let r_delta_g2 = deserialize_g2_wasm(&mut vec_delta_g2);
// ic
let vec_ic = bytes[432..576].to_vec();
// println!("\nic vector: {:?}", vec_ic);
let mut r_ic: Vec<G1Affine> = Vec::new();
let mut vec_ic_de = vec_ic[0..48].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
vec_ic_de = vec_ic[48..96].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
vec_ic_de = vec_ic[96..144].to_vec();
r_ic.push(deserialize_g1_wasm(&mut vec_ic_de));
// Reconstruct vk
// replace following if using bellman::{groth16, groth16::Proof};
// let deserialized_vk = groth16::VerifyingKey::<Bls12> {
let deserialized_vk = VerifyingKey {
alpha_g1: r_alpha_g1,
beta_g1: r_beta_g1,
beta_g2: r_beta_g2,
gamma_g2: r_gamma_g2,
delta_g1: r_delta_g1,
delta_g2: r_delta_g2,
ic: r_ic,
};
// Uncomment following if using bellman::{groth16, groth16::Proof};
// let pvk = groth16::prepare_verifying_key(&deserialized_vk);
// println!("Key reconstruction time: {:?}", start_key_recons.elapsed());
// ***** Reconstruct proof *****
// let start_proof_recons = Instant::now();
// proof.g1
let r_a = G1Affine::from_compressed(&bytes[576..624].try_into().unwrap())
.expect("Failed to deserialize a");
// proof.g2
let r_b = G2Affine::from_compressed(&bytes[624..720].try_into().unwrap())
.expect("Failed to deserialize b");
// proof.g1
let r_c = G1Affine::from_compressed(&bytes[720..768].try_into().unwrap())
.expect("Failed to deserialize c");
// Replace following if using bellman::{groth16, groth16::Proof};
// let r_proof: Proof<Bls12> = Proof{a: r_a, b: r_b, c: r_c};
let r_proof: Proof = Proof {
a: r_a,
b: r_b,
c: r_c,
};
// println!("Proof reconstruction time: {:?}", start_proof_recons.elapsed());
// ***** Reconstruct input *****
// let start_input_recons = Instant::now();
let last_64_bytes = &bytes[bytes.len() - 64..];
let r_inputs: Vec<Scalar> = last_64_bytes
.chunks(32) // Each Scalar in bls12_381 uses 32 bytes
.map(|chunk| {
Scalar::from_bytes(chunk.try_into().unwrap()).expect("Invalid bytes for Scalar")
})
.collect();
// println!("Input reconstruction time: {:?}", start_input_recons.elapsed());
/***** proof verification *****/
// uncomment following if bellman groth16 is used
// assert!(groth16::verify_proof(&pvk, &r_proof, &r_inputs).is_ok());
// let start_verify = Instant::now();
// Ensure the number of inputs matches the vk.ic length minus 1 (for IC[0])
if (r_inputs.len() + 1) != deserialized_vk.ic.len() {
return false;
}
/***** Compute linear combination: input_acc = IC[0] + sum(input[i] * IC[i+1]) *****/
let mut acc = deserialized_vk.ic[0].to_curve(); // Convert G1Affine to G1Projective
// Computes multi-scalar multiplication,
// which is a weighted sum of elliptic curve points.
// In Groth16, this builds the point:
// acc = IC₀ + input₁ × IC₁ + input₂ × IC₂ + ... + inputₙ × ICₙ
// Where: ICᵢ are fixed elliptic curve points (from the verifying key).
// inputᵢ are the public inputs to the circuit.
// Example: public_inputs = [x₁, x₂], vk.ic = [IC₀, IC₁, IC₂], acc = IC₀ + x₁ * IC₁ + x₂ * IC₂
// This binds the public inputs to the proof
for (input, ic_point) in r_inputs.iter().zip(&deserialized_vk.ic[1..]) {
acc += ic_point.to_curve() * input;
}
let acc_affine = acc.to_affine(); // converts the point acc from projective form back to affine form.
// Preparing G2 elements for pairing by converting them into G2Prepared format.
let proof_b_prepared = G2Prepared::from(r_proof.b);
let gamma_g2_prepared = G2Prepared::from(deserialized_vk.gamma_g2);
let delta_g2_prepared = G2Prepared::from(deserialized_vk.delta_g2);
let beta_g2_prepared = G2Prepared::from(deserialized_vk.beta_g2);
// Compute required product of pairings in their Miller loop form
// Groth16 verifier checks if e(A, B) * e(acc, γ)⁻¹ * e(C, δ)⁻¹ * e(α, β)⁻¹ == 1
// which boils down to
// let start_miller = Instant::now();
let ml_result = multi_miller_loop(&[
(&r_proof.a, &proof_b_prepared), // e(A,B)
(&(-acc_affine), &gamma_g2_prepared), // e(acc, γ)⁻¹
(&(-r_proof.c), &delta_g2_prepared), // e(C, δ)⁻¹
(&(-deserialized_vk.alpha_g1), &beta_g2_prepared), //e(α, β)⁻¹
]);
// println!("Miller time: {:?}", start_miller.elapsed());
// let start_final = Instant::now();
let result = ml_result.final_exponentiation();
// println!("Final time: {:?}", start_final.elapsed());
// println!("Proof verification time: {:?}", start_verify.elapsed());
// true
result == bls12_381::Gt::identity()
}

View File

@@ -131,7 +131,7 @@ print_wasm_error(std::string_view msg, wasm_trap_t* trap, beast::Journal jlog)
#ifdef DEBUG_OUTPUT
auto& j = std::cerr;
#else
auto j = jlog.error();
auto j = jlog.warn();
#endif
wasm_byte_vec_t error_message WASM_EMPTY_VEC;

View File

@@ -58,7 +58,6 @@ setCommonHostFunctions(HostFunctions* hfs, std::vector<WasmImportFunc>& i)
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);