Summary
Android production ANRs in synonymdev/bitkit-android#1036 show Node::list_peers blocked while acquiring PeerStore.peers.read().
PeerStore::add_peer and PeerStore::remove_peer currently retain peers.write() while persisting the updated peer set. With VssStore, the synchronous KVStoreSync::write bridges remote persistence through block_in_place and internal_runtime.block_on. A slow remote write therefore retains the peer-store write lock for network duration and blocks every synchronous list_peers reader.
Symbolicated production stack
The affected Bitkit v2.3.0 build 182 uses ldk-node-android:0.7.0-rc.46 from source commit 3ace915250296cbbc3069b2c23030d2cdf7ba834.
The released Bitkit APK, rc.46 Maven AAR, and committed rc.46 Android library contain the same arm64 ELF:
- size:
14,213,792 bytes
- SHA-256:
fbb450b145054f0682d966c5326cf88a477c9efd1c82b3c74e70d0bb7acabc48
.text: 0x561280..0xd338d0
The Play program counters are direct ELF VMAs. The exported uniffi_ldk_node_fn_method_node_list_peers symbol starts at 0x963f88; Play frame 0x963fc4 is +60 inside that function.
#00 bionic syscall
#01 0xcfa090 std futex wait / RwLock read contention
#02 0x661c5c std::sys::sync::rwlock::futex::RwLock::read_contended
#03 0x791a90 ldk_node::peer_store::PeerStore::list_peers
#04 0x79ba58 ldk_node::Node::list_peers
#05 0x60cfe8 UniFFI scaffolding for Node::list_peers
#06 0x619894 UniFFI callback wrapper for Node::list_peers
#07 0x963fc4 uniffi_ldk_node_fn_method_node_list_peers + 60
Source attribution:
src/peer_store.rs:44-72: add_peer and remove_peer retain self.peers.write() across persist_peers
src/peer_store.rs:74-75: list_peers acquires self.peers.read()
src/peer_store.rs:82-102: persist_peers calls KVStoreSync::write
src/io/vss_store.rs:191-219: VssStore::write waits for remote persistence through block_in_place and internal_runtime.block_on
The same lock scope remains on current fork main at a94255c88dff1c723fc1741dc52a5b4f664cb95f.
Required behavior
- Serialize peer mutations independently from peer snapshot reads.
- Restrict the peer
RwLock to the in-memory mutation and snapshot.
- Complete storage I/O after releasing the peer
RwLock.
- Preserve persistence failure and retry semantics.
- Add a concurrent regression test whose fake
KVStoreSync::write remains blocked while list_peers returns promptly.
- Bump the crate version, regenerate mobile bindings, and publish a release for Android and iOS consumption.
Upstream lightningdevkit#919 implemented this lock-scope pattern in commit d49b681.
Summary
Android production ANRs in synonymdev/bitkit-android#1036 show
Node::list_peersblocked while acquiringPeerStore.peers.read().PeerStore::add_peerandPeerStore::remove_peercurrently retainpeers.write()while persisting the updated peer set. WithVssStore, the synchronousKVStoreSync::writebridges remote persistence throughblock_in_placeandinternal_runtime.block_on. A slow remote write therefore retains the peer-store write lock for network duration and blocks every synchronouslist_peersreader.Symbolicated production stack
The affected Bitkit v2.3.0 build 182 uses
ldk-node-android:0.7.0-rc.46from source commit3ace915250296cbbc3069b2c23030d2cdf7ba834.The released Bitkit APK, rc.46 Maven AAR, and committed rc.46 Android library contain the same arm64 ELF:
14,213,792bytesfbb450b145054f0682d966c5326cf88a477c9efd1c82b3c74e70d0bb7acabc48.text:0x561280..0xd338d0The Play program counters are direct ELF VMAs. The exported
uniffi_ldk_node_fn_method_node_list_peerssymbol starts at0x963f88; Play frame0x963fc4is+60inside that function.Source attribution:
src/peer_store.rs:44-72:add_peerandremove_peerretainself.peers.write()acrosspersist_peerssrc/peer_store.rs:74-75:list_peersacquiresself.peers.read()src/peer_store.rs:82-102:persist_peerscallsKVStoreSync::writesrc/io/vss_store.rs:191-219:VssStore::writewaits for remote persistence throughblock_in_placeandinternal_runtime.block_onThe same lock scope remains on current fork
mainata94255c88dff1c723fc1741dc52a5b4f664cb95f.Required behavior
RwLockto the in-memory mutation and snapshot.RwLock.KVStoreSync::writeremains blocked whilelist_peersreturns promptly.Upstream lightningdevkit#919 implemented this lock-scope pattern in commit
d49b681.