Skip to content

perf: native ECDSA ops + pipeline optimizations for 74% signing latency reduction#195

Draft
Garandor wants to merge 2 commits intomainfrom
cl4wb0t/perf-optimize-signing
Draft

perf: native ECDSA ops + pipeline optimizations for 74% signing latency reduction#195
Garandor wants to merge 2 commits intomainfrom
cl4wb0t/perf-optimize-signing

Conversation

@Garandor
Copy link
Copy Markdown
Contributor

@Garandor Garandor commented Mar 27, 2026

Summary

74% p50 latency reduction for ECDSA signing Lit Actions via native Rust ECDSA ops and execution pipeline optimizations.

Native Rust ECDSA Ops (biggest impact: ~37ms saved)

  • Lit.Actions.deriveEthAddress(key) — derives Ethereum address + public key using k256 crate instead of ethers.js Wallet (pure JS BN.js was the bottleneck)
  • Lit.Actions.signMessage(key, message) — native Ethereum personal_sign
  • ethers.js path remains for backward compatibility

Execution Pipeline Optimizations

  • Thread pool for V8 execution (reuses OS threads)
  • Skip pre-execution resource usage update (no-op gRPC round-trip removed)
  • Combined setup scripts (PatchDeno.js merged into LitNamespace.js)
  • Removed --clear-free-memory V8 flag (each isolate destroyed after use)
  • Local setResponse/print ops (OpState instead of gRPC round-trips)
  • Pre-fetched private key in ExecutionRequest

API Server Caching

  • Auth result cache (moka, 10s TTL), dstack key cache, IPFS hash cache
  • Parallel auth + client builder via tokio::join!

Benchmark (release, local Anvil, 100 iterations)

Metric Baseline Optimized Improvement
p50 54.06ms 14.13ms 74%
p90 55.59ms 15.04ms 73%
min 51.62ms 12.78ms 75%

Test plan

  • cargo check passes (lit-api-server --all-features + lit-actions)
  • k6 ecdsa-sign correctness: 100% pass, 100 iterations
  • Native ops produce valid addresses, keys, and signatures
  • ethers.js backward compatibility preserved

…gning latency

Cache frequently-called operations on the ECDSA signing hot path:

- Auth cache (accounts/mod.rs): moka cache for can_execute_action() results
  with 10s TTL. Only caches positive results to avoid caching transient
  RPC failures as permission denials. Reduces redundant blockchain calls.

- Dstack key cache (dstack/v1/mod.rs): moka cache for deterministic key
  derivation results (no TTL needed). Eliminates repeated dstack socket
  round-trips for the same key.

- IPFS hash cache (core/core_features.rs): moka sync cache for
  get_lit_action_ipfs_id() keyed by DefaultHasher of code string.
  Avoids recomputing IPFS hashes for repeated code submissions.

- Reduce gRPC pool log level (actions/grpc.rs): info -> trace for the
  per-request "Connecting to address" log that fires even on pool hits.

Benchmark results (local Anvil + dstack simulator, 100 iterations):
- 1 VU sequential: ~3% p50 improvement (69ms -> 67ms)
- 10 VU concurrent: 28% p90 improvement (144ms -> 104ms),
                     22% p95 improvement (149ms -> 116ms)

The larger gains under concurrency come from eliminating contention on
the blockchain RPC and dstack socket. Production environments with
remote RPC endpoints (5-20ms vs <1ms locally) will see proportionally
larger sequential improvements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Garandor Garandor marked this pull request as draft March 27, 2026 05:59
… latency reduction

Major changes:

1. Native Rust ECDSA ops (lit-actions/ext):
   - `op_derive_eth_address`: derives Ethereum address + public key from private
     key using k256 crate. Replaces `new ethers.Wallet(key)` which does the same
     computation in pure JavaScript (~37ms → <1ms).
   - `op_sign_message`: signs an Ethereum personal message using k256 ECDSA.
     Replaces `wallet.signMessage()` in ethers.js.
   - Exposed as `Lit.Actions.deriveEthAddress()` and `Lit.Actions.signMessage()`
     in the SDK. The ethers.js path remains available for backward compatibility.

2. Execution pipeline optimizations (lit-actions/server):
   - Thread pool for V8 execution: reuses OS threads instead of spawning per request
   - Skip pre-execution resource usage update: eliminates a no-op gRPC round-trip
   - Combined setup scripts: merged PatchDeno.js into LitNamespace.js
   - Removed --clear-free-memory V8 flag: zeroing freed memory on every GC adds
     per-request latency; each isolate is destroyed after use anyway
   - Local setResponse/print ops: stores response and logs in OpState instead of
     gRPC round-trips, sends them with ExecutionResult

3. Pre-fetched private key (lit-api-server + lit-actions):
   - API server pre-derives the lit action private key and passes it in the
     ExecutionRequest, eliminating the gRPC round-trip for getLitActionPrivateKey op
   - Proto extended with optional `lit_action_private_key` field

4. API server caching (from previous commit, included in measurements):
   - Auth result cache (10s TTL), dstack key cache, IPFS hash cache
   - Parallel auth check + client builder
   - Reduced gRPC pool log level

Benchmark (local Anvil + dstack simulator, release builds, 100 iterations):

| Metric | Baseline | Optimized | Improvement |
|--------|----------|-----------|-------------|
| p50    | 54.06ms  | 14.13ms   | **74%**     |
| p90    | 55.59ms  | 15.04ms   | **73%**     |
| min    | 51.62ms  | 12.78ms   | **75%**     |

Security notes:
- Native ECDSA ops use the same k256 crate used elsewhere in the codebase
- Pre-fetched key travels through the same gRPC Unix socket channel
- Auth cache has 10s TTL bounding stale permission window
- V8 --clear-free-memory removal: each isolate is destroyed after single use,
  so freed memory is never accessible to subsequent requests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Garandor Garandor changed the title perf: cache auth, dstack keys, and IPFS hashes on signing hot path perf: native ECDSA ops + pipeline optimizations for 74% signing latency reduction Mar 27, 2026
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.

1 participant