Skip to content

[Bug]: Node.listBalances ANR in receive flow #1036

Description

@piotr-iohk

What happened?

Google Play Console reports a new production ANR cluster on Android mainnet 2.3.0 / build 182.

Play cluster label: split_config.arm64_v8a.apk | uniffi_ldk_node_fn_method_node_list_balances

The ANR occurs while the receive flow refreshes wallet state and calls into LDK Node through UniFFI/JNA:

ReceiveSheet -> WalletViewModel.refreshReceiveState -> LightningRepo.syncState -> LightningRepo.getBalances -> LightningService.getBalances -> Node.listBalances

Play Vitals release dashboard snapshot:

  • Release: 2.3.0 / build 182
  • Type: ANR
  • Affected users: 1
  • Events: 1
  • Share: 5.0%
  • Last occurred: ~4 days ago

Related epic: #986

Expected behavior

Opening the receive flow and refreshing wallet/Lightning state should not block input dispatching or trigger an ANR. Balance retrieval through Node.listBalances should complete quickly or be coordinated off the UI-critical path with timeout/error handling.

Steps to Reproduce

No deterministic repro confirmed. Suggested scenario from the Play stack:

  1. Use production mainnet Bitkit Android 2.3.0 / build 182.
  2. Open the receive flow.
  3. Allow ReceiveSheet to refresh receive state.
  4. App calls WalletViewModel.refreshReceiveState, then LightningRepo.syncState, then Node.listBalances.
  5. Observe Play ANR: input dispatching timed out.

Logs / Screenshots / Recordings

Play Console stack trace:

#00  pc 0x000000000009f7dc  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28)
#01  pc 0x0000000000cf9ef4  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#02  pc 0x0000000000661bd0  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#03  pc 0x00000000007b56c8  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#04  pc 0x000000000079c024  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#05  pc 0x00000000006183bc  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#06  pc 0x000000000061983c  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk
#07  pc 0x0000000000963e7c  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk (uniffi_ldk_node_fn_method_node_list_balances+68)
#08  pc 0x000000000001404c  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk (ffi_tramp_arch+30212096) (BuildId: 8549526bbd95df90b51b87eaf518d627a449eb24)
#09  pc 0x0000000000010a68  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk (ffi_tramp_free+30212096) (BuildId: 8549526bbd95df90b51b87eaf518d627a449eb24)
#10  pc 0x00000000000063c8  /data/app/.../to.bitkit.../split_config.arm64_v8a.apk (getCallbackAddress+30212096) (BuildId: 8549526bbd95df90b51b87eaf518d627a449eb24)
at com.sun.jna.Native.invokeStructure (Native method)
at com.sun.jna.Native.invokeStructure (Native.java:2196)
at com.sun.jna.Function.invoke (Function.java:448)
at com.sun.jna.Function.invoke (Function.java:364)
at com.sun.jna.Library$Handler.invoke (Library.java:270)
at java.lang.reflect.Proxy.invoke (Proxy.java:1009)
at org.lightningdevkit.ldknode.UniffiLib.uniffi_ldk_node_fn_method_node_list_balances (ldk_node.android.kt)
at org.lightningdevkit.ldknode.Node$listBalances$lambda$35$$inlined$uniffiRustCall$1.invoke (ldk_node.android.kt:14656)
at org.lightningdevkit.ldknode.Node$listBalances$lambda$35$$inlined$uniffiRustCall$1.invoke (ldk_node.android.kt:313)
at org.lightningdevkit.ldknode.UniffiRustCallStatusHelper.withReference (ldk_node.android.kt:413)
at org.lightningdevkit.ldknode.Node.listBalances (ldk_node.android.kt:14900)
at to.bitkit.services.LightningService.getBalances (LightningService.kt:1106)
at to.bitkit.repositories.LightningRepo.getBalances (LightningRepo.kt:1397)
at to.bitkit.repositories.LightningRepo.syncState (LightningRepo.kt:1326)
at to.bitkit.viewmodels.WalletViewModel$refreshReceiveState$1.invokeSuspend (WalletViewModel.kt:403)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:34)
at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith (DispatchedContinuation.kt:375)
at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable (Cancellable.kt:26)
at kotlinx.coroutines.CoroutineStart.invoke (CoroutineStart.kt:358)
at kotlinx.coroutines.AbstractCoroutine.start (AbstractCoroutine.kt:134)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch (Builders.common.kt:53)
at kotlinx.coroutines.BuildersKt.launch (unavailable:1)
at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default (Builders.common.kt:44)
at kotlinx.coroutines.BuildersKt.launch$default (unavailable:1)
at to.bitkit.viewmodels.WalletViewModel.refreshReceiveState (WalletViewModel.kt:401)
at to.bitkit.ui.screens.wallets.receive.ReceiveSheetKt$ReceiveSheet$2$1.invokeSuspend (ReceiveSheet.kt:59)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:34)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:100)
at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch (AndroidUiDispatcher.android.kt:79)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch (AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run (AndroidUiDispatcher.android.kt:57)
at android.os.Handler.handleCallback (Handler.java:1095)
at android.os.Handler.dispatchMessageImpl (Handler.java:135)
at android.os.Handler.dispatchMessage (Handler.java:125)
at android.os.Looper.loopOnce (Looper.java:269)
at android.os.Looper.loop (Looper.java:367)
at android.app.ActivityThread.main (ActivityThread.java:9333)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:566)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:929)

Bitkit Version

2.3.0 / build 182, production mainnet package to.bitkit.

Device / OS

TBD from Play Console details.

Reproducibility

Rarely (once or twice)

Additional context

This is part of the Play production crash/vitals follow-up tracked in #986.

This appears distinct from the existing native crash/timeout tickets:

This new cluster points to a blocking Node.listBalances call during receive-state refresh. It may still benefit from the ongoing Android native-symbol/release-chain hardening work, but the observed symptom is an ANR rather than a crash.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No fields configured for Bug.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions