prove({ prover: newLocalProver() }) is 18-49x slower than prove() with no argument
- Lingua principale
- TypeScript
- Stelle
- 1
- Fork
- 21
- Merge medio
- 12h 14m
- PR unite (30g)
- 41
Descrizione
Passing a prover to `prove()` is around fifty times slower than leaving the argument off, for the same transaction.
I hit this while timing proving for an app, and the gap was large enough that I assumed my measurement was wrong. It reproduces on the same request object, in the same page, back to back.
### Repro
```js
const script = await client.compile.txScript({
code: "use miden::core::sys\nbegin\n push.1 drop\n exec.sys::truncate_stack\nend\n",
});
const request = new TransactionRequestBuilder().withCustomScript(script).build();
// A — no prover argument
let staged = await client.transactions.executeRequest(account, request);
await staged.prove();
// B — explicit local prover
const prover = TransactionProver.newLocalProver();
staged = await client.transactions.executeRequest(account, request);
await staged.prove({ prover });
```
Timings on macOS, 8 cores, Chrome 152, `@miden-sdk/miden-sdk@0.15.9` single threaded, testnet:
```
A prove() 1925 ms 1267 ms
B prove({ prover }) 209043 ms 62244 ms
```
A second run on the same setup gave 2940 / 2726 ms for A and 53242 / 49823 ms for B. The later B call is faster than the first in both runs, so this is not degradation over time. The ratio lands between 18x and 49x depending on the run.
Both paths are local. I checked that by pulling the network down after the client was ready and the transaction executed, then calling `prove()` with no argument: it completed offline in 1742 ms. So the fast path is not delegating to a remote prover.
### Where the paths diverge
`proveResult` in the SDK sends the two cases to different calls, and `defaultProver` is null unless the app sets one:
```js
const prover = opts?.prover ?? defaultProver;
return prover
? await inner.proveTransaction(result, prover)
: await inner.proveTransaction(result);
```
The two branches resolve different provers: `custom_prover.get_prover()` versus `client.prover()`. `newLocalProver()` builds `LocalTransactionProver::new(ProvingOptions::default())`. I could not work out from here what `client.prover()` resolves to, so I am reporting the measurement rather than guessing at the cause.
This may be the same routing asymmetry described in #312, though that one is about `batch()` and the main thread, and here both calls go through the worker wrapper.
### Why it matters
`newLocalProver()` reads as the ordinary way to prove locally, and an app that wants local proving will reach for it. Nothing in the README or the API surface suggests the argument changes performance by this much. A note in the docs would help even if the behaviour is intended.
Environment: macOS, Chrome 152, node 24, pnpm 10.18, SDK 0.15.9, testnet.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Look at the `proveResult` function in the SDK to see the two branches: one with a prover argument and one without. Examine `client.prover()` and `LocalTransactionProver::new(ProvingOptions::default())` to understand the performance difference. Run the provided repro script to confirm timings, then profile both paths to identify bottlenecks. The fix likely involves aligning the prover configurations or optimizing the custom prover path.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- javascript, nodejs, typescript
- Ambito
- backend, performance
- Tipo di issue
- Bug
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Stato di attività
- Attiva
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 65/100