fix(wasm): unify error handling for mm2_main#2389
Conversation
894a385 to
64aa899
Compare
There was a problem hiding this comment.
@shamardy Thank you. I've tested the new wasm build, and it works reliably and provides much quicker feedback to the user than our previous approach.
With my testing of iOS today, I've realised we face the same issue for library builds where there's no reliable way for us to tell the result of the process and when it ended. This didn't come up because I hadn't tested failed login cases on iOS before today. Unfortunately, we can't ship iOS (even as a temporary measure) with the KDF executable bc of Apple's restrictions.
Native executable builds are different because Dart provides a callback for when the process has ended, and we can listen to the log output for that specific process to determine why it ended. In hindsight, KDF startup error handling has always been uniform across native vs wasm, but it's because of the non-uniform limitations on process handling of exe vs lib vs wasm.
Would it be a significant request to make the native function async with similar behaviour to the wasm build? Is that even possible since it's an exported C function? Alternatively, we could add an optional log callback argument to mm2_main, but this might not be ideal for you since it means an inconsistent mm2_main signature between native vs wasm.
I don't think that is possible, but I will look into it.
Will look into that and other alternatives. But I will do that in a different PR after this is reviewed and merged by @KomodoPlatform/mm2 team. |
|
@shamardy I mentioned in my bug report a suggestion about adding a dedicated SSE for the KDF lifecycle, but this may be overly complicated, and a simple, more sustainable solution is to have a callback parameter in |
mm2src/mm2_bin_lib/src/lib.rs
Outdated
| pub enum StartupErrorCode { | ||
| /// Operation completed successfully | ||
| Ok = 0, |
There was a problem hiding this comment.
It seems better to call this StartupResultCode instead of StartupErrorCode as it also includes success code.
There was a problem hiding this comment.
or remove this Ok variant all together and return () for success instead of i8.
There was a problem hiding this comment.
() is a Rust specific placeholder where 0 is known as a success code for any other languages.
There was a problem hiding this comment.
i mean remove the Ok variant all together from this enum.
the () suggestion is about the other functions in which we return Result<i8, Error>. there is no point of returning i8 in the success variant since it's already the Ok variant of the Result (unless we have different success types, which we currently don't).
There was a problem hiding this comment.
I understand that, what I am saying is that 0 is useful when converting things from other languages (which is the reason why we use this type).
There was a problem hiding this comment.
the () suggestion is about the other functions in which we return Result<i8, Error>. there is no point of returning i8 in the success variant since it's already the Ok variant of the Result (unless we have different success types, which we currently don't).
I opted for returning 0 from wasm (javascript) function to allow GUIs to handle the success case the same way if possible. I would ask for @CharlVS opinion on this and which would be better for GUIs.
I will rename this to StartupResultCode for now
There was a problem hiding this comment.
I will rename this to
StartupResultCodefor now
done
There was a problem hiding this comment.
If you want to keep this type compatible with FFI, you should keep 0 inside of it.
| if let Err(true) = LP_MAIN_RUNNING.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) { | ||
| log!("lp_main already started!"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
shouldn't we propagate this as an error back to the caller? do we?
| match block_on(mm2_main::lp_main( | ||
| params, | ||
| &ctx_cb, | ||
| KDF_VERSION.into(), | ||
| KDF_DATETIME.into(), | ||
| )) { |
There was a problem hiding this comment.
also errors from lp_main call
There was a problem hiding this comment.
Done f61bac7
I propagated them all as init errors for now, we might need new variants for lp_main errors later to propagate back additional better error codes.
CharlVS
left a comment
There was a problem hiding this comment.
The last commit was tested to work as expected, and there have been no regressions since my previous review.
|
I've tested to trigger a launch fails, which returned
I was unable to trigger When attempting to run a second instance of ./kdf with the same MM2.json file, I got Unsure how to trigger the other errors, let me know if it is simple enough. I recall there used to be a |
Was this using
Can you provide more info on this, I want to know where
for
Edit: Maybe fixing this #2389 (comment) and propgating errors back to caller will fix your issues @smk762 as I see we log only the errors of |
- Remove unnecessary Result return type from lp_run - Add channel-based communication for initialization status - Add configurable startup timeout with default of 60 seconds
|
can you please try again @smk762 for native, if the issue was native only. Edit: |
it was from binary. I'll setup to retest this as lib |
| log!("Failed to recover context in thread: {:?}", err); | ||
| return; |
There was a problem hiding this comment.
nit: we could panic here instead to trigger an erroneous log from the catch_unwind instead of "MM2 thread completed normally"
* dev: (26 commits) chore(deps): remove base58 and replace it completely with bs58 (GLEECBTC#2427) feat(tron): initial groundwork for full TRON integration (GLEECBTC#2425) fix(UTXO): improve tx fee calculation and min relay fee handling (GLEECBTC#2316) deps(timed-map): bump to 1.3.1 (GLEECBTC#2413) improvement(tendermint): safer IBC channel handler (GLEECBTC#2298) chore(release): complete v2.4.0-beta changelogs (GLEECBTC#2436) fix(event-streaming): initial addresses registration in utxo balance streaming (GLEECBTC#2431) improvement(watchers): re-write use-watchers handling (GLEECBTC#2430) fix(evm): make withdraw_nft work in HD mode (GLEECBTC#2424) feat(taproot): support parsing taproot output address types chore(RPC): use consistent param name for QTUM delegation (GLEECBTC#2419) fix(makerbot): add LiveCoinWatch price provider (GLEECBTC#2416) chore(release): add changelog entries for v2.4.0-beta (GLEECBTC#2415) fix(wallets): prevent path traversal in `wallet_file_path` and update file extension (GLEECBTC#2400) fix(nft): make `update_nft` work with hd wallets using the enabled address (GLEECBTC#2386) fix(wasm): unify error handling for mm2_main (GLEECBTC#2389) fix(tx-history): token information and query (GLEECBTC#2404) test(electrums): fix failing test_one_unavailable_electrum_proto_version (GLEECBTC#2412) improvement(network): remove static IPs from seed lists (GLEECBTC#2407) improvement(best-orders): return an rpc error when we can't find best orders (GLEECBTC#2318) ...
There was a significant inconsistency in how startup failures are handled between the native and WASM implementations of
mm2_main:i8valuesThis inconsistency made it difficult for web GUI to reliably detect when
mm2_mainfailed to start, which is particularly problematic when users were trying to log in. While native GUI can get immediate feedback on failure, web GUI had to use timeouts or other workarounds.Changes
This PR fixes the inconsistency by:
mm2_mainin wasm return a Promise (async fnwithResult<i8, JsValue>)StartupErrorCodeenum shared between native and WASMStartupErrortype with both code and descriptive message for the wasm implementation, allowing JavaScript to receive detailed error information.lp_mainas Promise rejections in the wasm implementation instead of just logging them.Architecture Improvement
As part of this fix, we've separated the previously combined initialization and runtime functionality into two distinct phases:
lp_main: Handles initialization and configuration, returns ctx when successfullp_run: Takes ctx fromlp_mainand manages runtime executionThis separation provides cleaner error boundaries, letting us properly propagate initialization errors before moving to the runtime phase. In the wasm implementation, we now resolve the Promise when initialization succeeds and spawn the runtime as a separate task, allowing JavaScript to immediately receive startup success/failure feedback.
This change not only fixes the error reporting inconsistency but also improves the overall architecture by better separating concerns between initialization and runtime execution.
fixes #2383