Draft
Conversation
Implement CoreBluetooth communication layer for BitBox02 Nova (Plus) hardware wallet on iOS: - Add Bluetooth.swift with BLE service/characteristic discovery, read/write operations, and u2fhid packet handling - Add BitboxFlutterPlugin.swift methods for iOS: initBitBox, getChannelHash, channelHashVerify, getETHAddress (all on background threads to avoid blocking UI) - Fix product mapping: bb02p-* now correctly maps to ProductBitBox02PlusMulti/PlusBTCOnly (not the non-Plus variants) - Fix BLE stale buffer issue: clear read buffer + drain semaphore before each new u2fhid init frame to prevent hwwRspBusy panics - Fix race condition: semaphore.signal() moved inside readBufferLock - Add 10s timeout on readBlocking to prevent hangs on BLE disconnect - Change InitDevice() from panic to bool return on error - Add pre-built Api.xcframework for iOS (gomobile bind) - Add channelHash and channelHashVerify to Dart platform interface
Prevents blocking the main thread during DFX auth signing when BitBox device communication is required.
Author
Code ReviewMust fix
Should fix
|
Move signETHRLPTransaction and signETHTypedMessage to DispatchQueue.global().async to prevent blocking the main thread during device communication.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The bitbox_flutter plugin had no iOS support — only Android was implemented. Adding iOS BLE support for BitBox02 Nova required solving several protocol-level issues specific to Bluetooth LE communication.
Key issues discovered and fixed
1. Wrong product mapping (
bb02p-multi→ProductBitBox02Multi)The BitBox02 Nova is a "Plus" device, but we mapped its BLE product string
bb02p-multitoProductBitBox02Multi(original BitBox02) instead ofProductBitBox02PlusMulti. This caused the Go firmware API to use wrong protocol paths — encrypted queries after pairing (e.g.ETHGetAddress) would hang because the device expected Plus-specific message formats.2. BLE stale buffer causing
panic: unexpected hwwRspBusyUnlike USB (synchronous request/response), BLE delivers notifications asynchronously. The device sometimes sends
hwwRspNotreadyfollowed byhwwRspBusyfor the same request. The second response would land in the read buffer during the Go retry sleep (200ms). When Go then senthwwReqRetryand read the response, it consumed the stalehwwRspBusyinstead of the actual retry response, causing a panic.Fix: Clear the read buffer + drain the semaphore before each new u2fhid init frame write. This ensures stale notifications from previous exchanges are discarded. The semaphore signal was also moved inside
readBufferLockto prevent a race condition betweenclearReadBuffer()and the BLE notification handler.3.
InitDevice()panics on errorThe Go API's
InitDevice()calledpanic(err)on failure (e.g. device disconnect during pairing), crashing the entire app. Changed to returnbool.4. Blocking main thread
channelHashVerify,getETHAddress, andsignETHMessageall send encrypted queries to the device and block until a response arrives. Running these on the Flutter main thread froze the UI. Moved all device-querying methods toDispatchQueue.global().async.5. Read timeout
readBlocking()usedsemaphore.wait()without timeout. If the BLE connection dropped withoutdidDisconnectPeripheralbeing called (e.g.XPC connection interrupted), the app would hang forever. Added a 10-second timeout.Test plan