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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions