Conversation
There was a problem hiding this comment.
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-bridgecdylibexporting 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) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change adds another Java example.