perf: native ECDSA ops + pipeline optimizations for 74% signing latency reduction#195
Draft
perf: native ECDSA ops + pipeline optimizations for 74% signing latency reduction#195
Conversation
…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>
… 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>
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.
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_signExecution Pipeline Optimizations
API Server Caching
Benchmark (release, local Anvil, 100 iterations)
Test plan