Skip to content

Java example (using Web Assembly and Chicory) - #8

Open
rkeene wants to merge 7 commits into
mainfrom
feature/java-wasm-example
Open

rkeene wants to merge 7 commits into
mainfrom
feature/java-wasm-example

Conversation

@rkeene

@rkeene rkeene commented Jun 19, 2026

Copy link
Copy Markdown
Member

This change adds another Java example.

@rkeene
rkeene requested a review from Copilot June 19, 2026 21:52
@rkeene rkeene added the java label Jun 19, 2026
@rkeene rkeene changed the title Java Web Assembly Example Java example (using Web Assembly and Chicory) Jun 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Java example that drives the Keeta Network Rust crates via a WASM “bridge” module (loaded with Chicory), providing Java wrappers for accounts/operations/blocks plus an HTTP-based UserClient to request votes, build vote staples (in WASM), and publish blocks. This fits the examples area by demonstrating end-to-end multisig block construction and submission from Java without JNI-native linking.

Changes:

  • Introduces a Rust wasm-bridge cdylib exporting a C-style API for account derivation, signing, block building/signing, and vote-staple utilities.
  • Adds Java bindings/wrappers (KeetaNetWasmBridge, KeetaNetJNI, Account, Operation, Block, UserClient) and an executable example (AccountsMultisigSigner).
  • Provides build/run automation and docs (Makefile, README, gitignores, Cargo manifests/locks).

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
contrib/java/accounts-multisig-signer/wasm-bridge/src/lib.rs WASM-exported C ABI surface for accounts/blocks/votes, plus in-module handle registry.
contrib/java/accounts-multisig-signer/wasm-bridge/Cargo.toml Declares the WASM bridge crate as a cdylib with keetanetwork dependencies.
contrib/java/accounts-multisig-signer/wasm-bridge/Cargo.lock Locks transitive dependencies for the WASM bridge crate.
contrib/java/accounts-multisig-signer/wasm-bridge/.gitignore Ignores WASM bridge build output.
contrib/java/accounts-multisig-signer/src/main/rust/lib.rs JNI shim exposing similar functionality to Java (separate from the WASM path).
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/UserClient.java Java HTTP client for head/balance/vote/publish with retry/recovery behavior.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/Permissions.java Loads and exposes permission bit constants from the native layer.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/Operation.java Java native-handle wrapper for block operations.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/KeetaNetWasmBridge.java Chicory WASM loader + memory helpers for calling exported functions.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/KeetaNetJNI.java Public Java facade over the WASM bridge exports, including handle tracking.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/Block.java Java fluent builder for unsigned/signed blocks using native handles.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/AccountsMultisigSigner.java End-to-end multisig + token example program mirroring the TS example.
contrib/java/accounts-multisig-signer/src/main/java/network/keeta/examples/Account.java Java native-handle wrapper for accounts, derivation, signing, and identifiers.
contrib/java/accounts-multisig-signer/README.md Documentation for the Java WASM multisig example and how to run it.
contrib/java/accounts-multisig-signer/Makefile Build/run automation: builds WASM, fetches Chicory jars, compiles/runs Java.
contrib/java/accounts-multisig-signer/Cargo.toml Declares a JNI cdylib crate for the Java example (Rust side).
contrib/java/accounts-multisig-signer/.gitignore Ignores build output for the Java example directory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +124 to +126
let total_len = count as usize * 8;
// SAFETY: caller supplies a contiguous u64 array in wasm memory.
let bytes = unsafe { slice::from_raw_parts(ptr as *const u8, total_len) };
Comment on lines +142 to +145
let total_len = count as usize * 8;
// SAFETY: caller supplies a contiguous array of u32 ptr/len pairs.
let bytes = unsafe { slice::from_raw_parts(ptr as *const u8, total_len) };
let mut out = Vec::with_capacity(count as usize);
Comment on lines +106 to +109
public static long accountFromSeed(String seedHex, int index, int keyType) {
byte[] seed = seedHex.getBytes(StandardCharsets.UTF_8);
long seedPtr = WASM.allocAndWrite(seed);
try {
Comment on lines +153 to +156
public static long generateIdentifier(long accountPtr, int identifierType, byte[] blockHash, int operationIndex) {
long hashPtr = 0;
int hashLen = 0;
if (blockHash != null && blockHash.length > 0) {
Comment on lines +188 to +195
public static byte[] signMessage(long accountPtr, byte[] message) {
long ptr = WASM.allocAndWrite(message);
try {
return WASM.callBytes("kn_sign_message", accountPtr, ptr, Integer.toUnsignedLong(message.length));
} finally {
WASM.free(ptr, message.length);
}
}
Comment on lines +197 to +213
public static int verifySignature(long accountPtr, byte[] message, byte[] signature) {
long messagePtr = WASM.allocAndWrite(message);
long sigPtr = WASM.allocAndWrite(signature);
try {
return WASM.callI32(
"kn_verify_signature",
accountPtr,
messagePtr,
Integer.toUnsignedLong(message.length),
sigPtr,
Integer.toUnsignedLong(signature.length)
);
} finally {
WASM.free(messagePtr, message.length);
WASM.free(sigPtr, signature.length);
}
}
Comment on lines +96 to +102
public Builder signer(Account signer) {
if (closed) {
throw new IllegalStateException("Builder has been closed");
}

long builderPtr = KeetaNetJNI.blockBuilderSetSigner(getNativePtr(), signer.getNativePtr());
updateHandle(builderPtr);
Comment on lines +133 to +141
public Builder signer(Account multisig, Account[] signers) {
if (closed) {
throw new IllegalStateException("Builder has been closed");
}

long[] signerPtrs = new long[signers.length];
for (int i = 0; i < signers.length; i++) {
signerPtrs[i] = signers[i].getNativePtr();
}
Comment on lines +18 to +22
5. Transmitting both signed blocks as vote staples using Java HTTP networking (`/vote`, `/node/publish`)
with vote staple construction done by Rust/WASM
6. Handling `LEDGER_SUCCESSOR_VOTE_EXISTS` by waiting for representative vote expiry and retrying transmit
6. Requesting testnet faucet funds before transmitting (same as the TypeScript example)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants