Skip to content

Nanox so fix#4

Merged
ImplOfAnImpl merged 3 commits into
feature/refactor-too-bigfrom
nanox_so_fix
Jun 16, 2026
Merged

Nanox so fix#4
ImplOfAnImpl merged 3 commits into
feature/refactor-too-bigfrom
nanox_so_fix

Conversation

@ImplOfAnImpl

@ImplOfAnImpl ImplOfAnImpl commented May 28, 2026

Copy link
Copy Markdown
Collaborator

The reason why tests in feature/refactor-too-big crash is stack overflow, which happens because some large objects are passed/returned/moved by value. I fixed the crash by boxing them.

I documented my findings about the apps stack usage in docs/memory_usage.md (in particular, how to measure it), but in short: passing, returning or even moving around large objects eats up large amounts of stack space and currently we only have less than 12KB of it on nanox.

Details:
sizeofs of some objects in feature/refactor-too-big:
TxParsingInputsContext: 688
SignTxReq: 264
mlcp::SighashInputCommitment: 208
TxInputReq: 264
TxOutputReq: 192
Response: 100
NbglStreamingReview: 48

I boxed those with sizes around 200 bytes or more.

Original stack frame sizes (sorted by frame size, bigger first):

7792    mintlayer_app::handlers::sign_tx::handle_sign_tx
3952    mintlayer_app::handle_command
1384    sample_main
1336    mintlayer_app::app_ui::utils::bech32m_encode
880     <mintlayer_core_primitives::tx_output::TxOutput as parity_scale_codec::codec::Decode>::decode::<&[u8]>
592     ledger_device_sdk::exiting_panic
512     mintlayer_app::app_ui::sign::format_lock
384     <alloc::collections::btree::map::entry::Entry<mintlayer_app::handlers::sign_tx::summary_collector::CoinOrTokenId, mintlayer_core_primitives::misc::Amount>>::or_insert
360     mintlayer_app::handlers::utils::mintlayer_hash
328     <ledger_device_sdk::io_legacy::Comm>::decode_event::<ledger_device_sdk::io_legacy::ApduHeader>
304     <ledger_device_sdk::io_legacy::Comm>::apdu_send
288     <ledger_device_sdk::hash::blake2::Blake2b_512 as ledger_device_sdk::hash::HashInit>::new
144     <ledger_device_sdk::ecc::Secp256k1 as ledger_device_sdk::ecc::SeedDerive>::derive_from
136     <mintlayer_core_primitives::crypto::PublicKey as parity_scale_codec::codec::Decode>::decode::<&[u8]>
128     <mintlayer_core_primitives::misc::Amount as parity_scale_codec::codec::Decode>::decode::<&[u8]>
112     mintlayer_app::handlers::sign_message::schnorr_sign::<32>
104     compiler_builtins::mem::memmove
104     <ledger_device_sdk::nbgl::nbgl_streaming_review::NbglStreamingReview>::next
104     <u128>::_fmt
104     mintlayer_app::app_ui::sign::format_value
...

A sidenote: one interesting thing is that if I marked fn decode_all as #[inline(never)], then I could see:

1440	messages::decode_all::<messages::SignTxReq>

I.e. more than 1 KB of stack usage above may be attributed to the inlined decode_all (not that we can do much about it, just an observation).

After boxing each variant of TxParsingContext I got:

3152    mintlayer_app::handlers::sign_tx::handle_sign_tx
2384    mintlayer_app::handle_command
1384    sample_main
...

Then I boxed by-value self in XxxContext methods:

2520    mintlayer_app::handlers::sign_tx::handle_sign_tx
2384    mintlayer_app::handle_command
1384    sample_main

Then I boxed the contents of SignTxReq and made the correspondent handle_ functions accept Box:

1896	mintlayer_app::handlers::sign_tx::handle_sign_tx
1648	mintlayer_app::handle_command
1384	sample_main
...

After removing "chain-error" from parity-scale-codec's features, the compiler decided to inline handle_command and I got:

2984	sample_main
1896	mintlayer_app::handlers::sign_tx::handle_sign_tx
1336	mintlayer_app::app_ui::utils::bech32m_encode
...

But note that the new total size of sample_main and handle_sign_tx stack frames is less than the old total size of sample_main+handle_command+handle_sign_tx.

For clarity I also recompiled it with handle_command marked with #[inline(never)]:

1896	mintlayer_app::handlers::sign_tx::handle_sign_tx
1544	mintlayer_app::handle_command
1384	sample_main
...

So removing "chain-error" reduced handle_command's stack usage by about 100 bytes. Not a big deal, but on the other hand we don't benefit from "chain-error" in any way, because we never examine decoding errors and don't even print them.

For comparison, frame sizes in feature/mintlayer-app are:

4792	mintlayer_app::handle_command
2112	sample_main
1336	mintlayer_app::app_ui::utils::bech32m_encode
1008	<mintlayer_core_primitives::tx_output::TxOutput as parity_scale_codec::codec::Decode>::decode::<&[u8]>
...

P.S.

  1. The tests in this branch still fail when run without --golden_run, because the snapshots are outdated.
  2. I also bumped ledger_secure_sdk_sys version to 1.16.1 (same as in feature/mintlayer-app) - this is just to make results in the two branches comparable.

@ImplOfAnImpl ImplOfAnImpl marked this pull request as ready for review May 28, 2026 09:28
@ImplOfAnImpl ImplOfAnImpl requested a review from OBorce May 28, 2026 09:29
@ImplOfAnImpl ImplOfAnImpl merged commit 89e9fb0 into feature/refactor-too-big Jun 16, 2026
34 of 35 checks passed
@ImplOfAnImpl ImplOfAnImpl deleted the nanox_so_fix branch June 16, 2026 16:30
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.

2 participants