Skip to content

Pipeline + Go, Wasm, Java, Rust examples#65

Merged
mihaimarcu2004 merged 15 commits intomainfrom
pipeline
Apr 28, 2026
Merged

Pipeline + Go, Wasm, Java, Rust examples#65
mihaimarcu2004 merged 15 commits intomainfrom
pipeline

Conversation

@mihaimarcu2004
Copy link
Copy Markdown
Contributor

@mihaimarcu2004 mihaimarcu2004 commented Apr 23, 2026

Summary

Adds a CI pipeline and fills in cross-language testing/examples for the signer library.

Took the examples from and put them under examples.
#62
#59

CI (.github/workflows/ci.yml)

  • New CI workflow that runs on every push, PR, and workflow_dispatch.
  • build-and-test job (ubuntu-latest): sets up Go 1.23.1, Node 22, Temurin JDK 21, Rust stable, and just; runs go test ./..., then just build-linux-local, just build-wasm, the WASM Node smoke test, just build-java, and just build-rust. Uploads the Linux .so/.h, .wasm, and wasm_exec.js as artifacts.
  • build-darwin job (macos-14): runs just build-darwin-local, compiles the C++ example against the produced .dylib, and uploads the darwin arm64 .dylib.

Go tests (client/sign_test.go)

  • Adds unit tests for TxClient: TestGenerateAPIKey, TestCreateClient, and sign-tests for cancel-order, cancel-all-orders, create-order, create-sub-account, update-leverage, and create-grouped-orders. Asserts tx hashes are deterministic for fixed inputs and that the SkipNonce attribute is correctly toggled via L2TxAttributes.

WASM smoke test (examples/wasm/test_wasm.mjs)

  • New Node script that instantiates build/lighter-signer.wasm via wasm_exec.js, calls GenerateAPIKey / CreateClient, signs cancel-order, cancel-all-orders, create-order, create-sub-account, and update-leverage txs, and verifies txType / txHash / decoded txInfo. Also toggles skipNonce and asserts the hash and L2TxAttributes change.

Java example (examples/java/)

  • New Maven module (pom.xml, src/main/java/LighterLib.java, Example.java) with JNA bindings to the shared library and a benchmark that spawns 5 threads, each generating a key, creating a client on chain 304, obtaining a 7h auth token, and signing 100 create/cancel pairs back-to-back.

Rust example (examples/rust/)

  • New Cargo crate (Cargo.toml, Cargo.lock, src/lib.rs, src/main.rs) with FFI bindings to the shared library and the equivalent 5-thread / 100 create+cancel benchmark.

Examples reorg & docs

  • Moves the existing examples/example.cpp to examples/cpp/example.cpp.
  • Rewrites examples/README.md to document prerequisites, build, and run instructions for C++, Java, Rust, and WASM.
  • justfile: adds build-java and build-rust recipes.
  • .gitignore: ignores Java/Rust build outputs.

Review & Testing Checklist for Human

  • Confirm the CI job versions (Go 1.23.1, Node 22, Java 21, Rust stable) match what the team wants to support long-term.
  • Verify the build-darwin job actually produces a working .dylib on macos-14 (the rest of CI currently passes but this macOS runner is new).
  • Sanity-check that go test ./... in client/sign_test.go uses hardcoded keys/nonces that are safe to commit (they look like throwaway test vectors, but worth a second pair of eyes).
  • Run the Java and Rust benchmarks locally at least once to confirm the 5-thread / 100-tx loop completes cleanly against the shared library you built from this branch.

Notes

  • CI is currently 4 passing / 1 pending on this branch.
  • on: push triggers the workflow for all branches, not just PRs — let me know if you'd rather scope it to main + PRs only.

Link to Devin session: https://app.devin.ai/sessions/c8654b9063d64a73ae24ad8f31c2ee40
Requested by: @mihaimarcu2004


Open in Devin Review

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@mihaimarcu2004 mihaimarcu2004 changed the title Pipeline + Go and Wasm tests Pipeline + Go, Wasm, Java, Rust examples Apr 23, 2026
Copy link
Copy Markdown

@zen zen left a comment

Choose a reason for hiding this comment

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

Please see my comments

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml Outdated
- uses: actions/upload-artifact@v4
with:
name: lighter-go-darwin
path: build/lighter-signer-darwin-arm64.dylib No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

We also would need:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

to prevent multiple pushes creating queue

Also for all external actions we need to pin them to SHA instead of tag (tags are mutable and prone to suplply chain attacks) .e.g.

uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

All actions with SHAs:

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683       # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff         # v5
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020       # v4
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9       # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8   # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32      # v2
- uses: extractions/setup-just@dd310ad5a97d8e7b41793f8ef055398d51ad4de6   # v2
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02  # v4

No release workflow right now. CI uploads artifacts, but nothing creates a GitHub Release on tag or attaches the binaries. Looks like the existing releases were done manually — might be worth automating at some point.

darwin/amd64 (Intel Mac) isn’t built in CI. macos-14 only covers arm64, so if you’re still shipping Intel dylibs, they’re not being verified.

Artifact retention isn’t explicitly set (so it defaults to 90 days). That’s fine for now, but could be worth setting it explicitly.

Running Java and Rust in the same Ubuntu job adds quite a bit of setup time. If builds start getting slow, it might make sense to split them into separate jobs.

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml Outdated
@devin-ai-integration
Copy link
Copy Markdown
Contributor

Review Summary

Overall this is a solid PR — CI pipeline is well-structured (SHA-pinned actions, concurrency groups, go-version-file), Go tests are thorough, and the cross-language examples provide good coverage. The previous review feedback from zen and alexvelea has been addressed. A few things worth flagging:

Memory leaks in Rust & Java FFI wrappers

Both lib.rs and LighterLib.java copy C-allocated strings from the shared library but never free the originals. Every call to sign_*, generate_api_key, or create_auth_token leaks the strings returned in the response structs.

  • Rust: ptr_to_string copies via CStr::from_ptr().to_string_lossy().into_owned() but the original *mut c_char is never passed to Free. The free method exists on LighterLib but is unused.
  • Java: SignedTxResponse, ApiKeyResponse, and StrOrErr structs contain JNA-mapped String fields that JNA copies, but the underlying C pointers are never freed. Lib.Free(Pointer) is declared but never called.

For a short-lived benchmark this doesn't matter, but since lib.rs is published as a [lib] target in Cargo.toml, users copying the bindings will inherit the leaks. Consider either:

  1. Adding Free calls in raw_to_signed_tx / conversion helpers (after copying), or
  2. Documenting the leak explicitly in a comment so consumers know to handle it.

Go tests: unchecked GenerateAPIKey() errors

TestSignCancelOrder, TestSignCancelAllOrders, TestSignCreateOrder, TestSignCreateSubAccount, TestSignUpdateLeverage, and TestSignCreateGroupedOrders all ignore the error from GenerateAPIKey():

priv, _, _ := GenerateAPIKey()

If it fails, priv is empty and newTestClient will fail with an unrelated error. Could replace with the same pattern used in TestGenerateAPIKey and TestCreateClient:

priv, _, err := GenerateAPIKey()
if err != nil {
    t.Fatalf("GenerateAPIKey error: %v", err)
}

Missing trailing newlines

12 files in this PR are missing a final newline (.gitignore, justfile, pom.xml, Example.java, LighterLib.java, Cargo.toml, lib.rs, main.rs, README.md, etc.). Minor POSIX nit — some tools/linters warn on this.

CI nits

  1. apt-get install without apt-get update (line 55 of ci.yml): The runner's package index can go stale, causing gcc-mingw-w64-x86-64 installs to occasionally fail. Adding sudo apt-get update before the install is safer.
  2. darwin job no longer runs examples/tests — it only builds the dylib. This reduces macOS test coverage compared to the Linux job. Intentional?
  3. build-cpp justfile recipe hardcodes lighter-signer-linux.so — works for CI but can't be used on macOS. Might be worth a note or a platform-conditional recipe.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Comment thread .github/workflows/ci.yml

- name: Cross-compile Windows DLL
run: |
sudo apt-get install -y gcc-mingw-w64-x86-64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: The runner's package index can go stale. Consider adding sudo apt-get update before the install to avoid intermittent resolution failures:

run: |
  sudo apt-get update
  sudo apt-get install -y gcc-mingw-w64-x86-64

Every call to Sign*, GenerateAPIKey, CreateAuthToken, CreateClient, and
CheckClient returns structs containing C.CString pointers (malloc'd by
the Go shared library). The wrappers copied these strings into managed
memory but never called the exported Free() function, leaking the
originals.

Rust:
- Cache the Free symbol as a raw fn pointer on LighterLib::load().
- Pass free_fn into ptr_to_string() and raw_to_signed_tx() so every
  copied pointer is freed immediately after conversion.
- All 22 affected methods now free automatically.

Java:
- Change String fields to Pointer in StrOrErr, ApiKeyResponse, and
  SignedTxResponse structs.
- Add readAndFree(Lib) helper that reads the string and calls Lib.Free.
- Update Example.java to use the new API.

C++:
- Add Free() calls for all returned char* fields in example.cpp.

Co-Authored-By: mihai <mihai2004marcu@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@mihaimarcu2004 mihaimarcu2004 requested a review from zen April 27, 2026 13:57
Comment thread .github/workflows/ci.yml
curl -fsSL "https://raw.githubusercontent.com/golang/go/${GO_VERSION}/lib/wasm/wasm_exec.js" \
-o ./build/wasm_exec.js \
|| curl -fsSL "https://raw.githubusercontent.com/golang/go/${GO_VERSION}/misc/wasm/wasm_exec.js" \
-o ./build/wasm_exec.js
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why we've changed the approach?
The previous approach (cp from $(go env GOROOT)) was more reliable — the file is already on the runner since Go is installed. This adds an external network call that can fail, and it depends on GOVERSION matching the GitHub tag exactly.

Comment thread .github/workflows/ci.yml
Copy link
Copy Markdown

@zen zen left a comment

Choose a reason for hiding this comment

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

LGTM!

@mihaimarcu2004 mihaimarcu2004 merged commit f9b2c26 into main Apr 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants