# Bindings Upgrade to the 1.0 API # TODOs - [x] TODO 1: Should we keep this? We'll need to pin dependencies - [x] TODO 2: Other CI workflows use explicit Rust compiler versions, I think we should do the same here - [x] TODO 3: Other CI workflows use explicit version of the Rust compiler, I think we should do the same here - [ ] TODO 4: I DON'T KNOW IF THIS IS A DECENT WAY TO GENERATE ENTROPY PLEASE CONFIRM - [x] TODO 6: Why are these imports required? - [ ] TODO 7: It appears that the to_hex() method is not available anymore. Look into the correct way to pull the hex out of the DescriptorSecretKey. Note: ToHex was removed in bitcoin_hashes 0.12.0 - [ ] TODO 8: Do we really need the mutex on the wallet? Could this be an Arc? - [ ] TODO 9: Peek is not correctly implemented - [ ] TODO 10: Do we need this mutex? - [x] TODO 11: Handle error correctly by rethrowing it as a BdkError - [ ] TODO 16: Why is the Arc required here? - [ ] TODO 17: I have not verified that this will work and have a suspicion it does not based on vague memories of conversations we had in the past - [ ] TODO 18: Migrate hard coded strings to constants all in the same location so they're at least easy to find and reason about. - [x] TODO 20: Add this to the publishing script! - [x] TODO 21: Add this to the publishing script! - [ ] TODO 22: Issues with openssl and cross-compilation. See [PR 1179](https://github.com/bitcoindevkit/bdk/pull/1179) for a fix. - [ ] TODO 23: Add TODO 24 to the source code - [ ] TODO 24: We should offer the full SignOptions enum instead of forcing the default <br> <br> <br> # Notes ### Issue with openssl :::success I think the solution for this is in https://github.com/bitcoindevkit/bdk/pull/1179 ::: On macOS, here is what I have done so far: ```bash brew install openssl export OPENSSL_DIR=/opt/homebrew/Cellar/openssl@3/3.1.3 ``` The above seems to have solved the aarch64 build. Now problems with the arm-v7. Because we're manually adding the environment variable for the openssl library, the cross-compilation now fails (you can't build the x86_64 and the armv7a libraries on macOS). The solutiion appears to either download them pre-built, or build them locally and point to those builds. Not sure yet what is the best option. **Python build not working on Ubuntu image** Python for the Linux builds was using manylinux, which means the package manager is yum. Needed to change the command to use it instead of apt-get ```yaml # this doesn't work - name: Install OpenSSL dependencies run: sudo apt-get update && sudo apt-get install -y libssl-dev # instead use this - name: "Install OpenSSL dependencies" run: yum install -y openssl-devel ``` When cleaning up the PR I found this which allows the Android build to build on the CI but only for the aarch64-v8a build. Keeping it here for archives. ```yaml # TODO 21: Add this to the publishing script! This openssl library is required for the async esplora # crate at this point. See TODO 22 for more info. - name: "Install OpenSSL dependencies" run: sudo apt-get update && sudo apt-get install -y libssl-dev ``` Same for Python here: ```yaml # TODO 20: Add this to the publishing script! # For the Linux builds, you'll run into errors on compilation because Rust cannot find the openssl library. # To solve this we install them explicitly here - name: "Install OpenSSL dependencies" run: yum install -y openssl-devel ``` Same for Swift here in the Package.swift file: ```txt .target( name: "BitcoinDevKit", dependencies: ["bdkFFI"], swiftSettings: [.unsafeFlags(["-suppress-warnings"])] swiftSettings: [.unsafeFlags(["-suppress-warnings"])], linkerSettings: [ .linkedFramework("SystemConfiguration", .when(platforms: [.macOS, .iOS, .tvOS, .watchOS])) ] ), ``` ### Questions around use of Arc Read the [ADR from Mozilla](https://github.com/mozilla/uniffi-rs/tree/main/docs/adr) on Arc. ## Sync and Scan This was on the Esplora client. ```rust pub fn sync( &self, wallet: Arc<Wallet>, sync_options: SyncOptions, stop_gap: u64, parallel_requests: u64, ) -> Result<Arc<Update>, BdkError> { } pub fn scan( &self, spks: HashMap<KeychainKind, Arc<SpkIterator>>, local_chain: &LocalChain, previous_tip: Option<CheckPoint>, stop_gap: u32, parallel_requests: u64, ) -> Result<Arc<Update>, BdkError> { let hash_map = spks .iter() .map(|(keychain, spk_iterator)| { (keychain.clone(), spk_iterator.deref().0.lock().unwrap().to_owned()) }); let btree_map = BTreeMap::from_iter(hash_map); let (update_graph, last_active_indices) = self .0 .scan_txs_with_keychains( btree_map, core::iter::empty(), core::iter::empty(), stop_gap as usize, parallel_requests as usize, ) .unwrap(); let missing_heights = update_graph.missing_heights(local_chain); let chain_update = self .0 .update_local_chain(previous_tip, missing_heights) .unwrap(); let update = BdkUpdate { last_active_indices, graph: update_graph, chain: Some(chain_update), }; Ok(Arc::new(Update(update))) } ``` This was in the wallet module. ```rust pub fn spks_of_all_keychains(&self) -> HashMap<KeychainKind, Arc<SpkIterator>> { let all_spks = self .get_wallet() .spk_index() .spks_of_all_keychains() .into_iter() .fold(HashMap::new(), |mut map, (keychain, iter)| { let spk_iter = SpkIterator(Mutex::new( iter, )); map.insert(keychain, Arc::new(spk_iter)); map }); all_spks } #[derive(Debug)] pub struct IndexedScript { pub index: u32, pub script: Arc<Script>, } pub struct SpkIterator(pub(crate) Mutex<BdkSpkIterator<BdkDescriptor<DescriptorPublicKey>>>); impl SpkIterator { pub fn new(descriptor: Arc<Descriptor>) -> SpkIterator { Self(Mutex::new(BdkSpkIterator::new( descriptor.extended_descriptor.clone(), ))) } pub fn next(&self) -> Option<IndexedScript> { let mut bdk_spk_iterator = self.0.lock().unwrap(); bdk_spk_iterator .next() .map(|(index, script)| IndexedScript { index, script: Arc::new(script.into()), }) } } ``` Part of the tests. ```rust #[test] fn test_spks_of_all_keychains() { let descriptor = Descriptor::new( "wpkh(tprv8ZgxMBicQKsPf2qfrEygW6fdYseJDDrVnDv26PH5BHdvSuG6ecCbHqLVof9yZcMoM31z9ur3tTYbSnr1WBqbGX97CbXcmp5H6qeMpyvx35B/84h/1h/0h/0/*)".to_string(), Network::Testnet ).unwrap(); let wallet = Wallet::new_no_persist(Arc::new(descriptor), None, Network::Testnet).unwrap(); let spks = wallet.spks_of_all_keychains(); spks.iter().for_each(|(keychain, spk_iter)| { dbg!(keychain); assert_eq!(*keychain, KeychainKind::External); let mut spks_iter = spk_iter.0.lock().unwrap().clone(); let next_addr = spks_iter.next().map(|(i, s)| { ( i, Address::from_script(s.as_script(), bitcoin::Network::Testnet) .unwrap() .to_string(), ) }); let expected_addr = "tb1qrnfslnrve9uncz9pzpvf83k3ukz22ljgees989".to_string(); assert!(matches!(next_addr, Some((i, addr)) if i == 0 && addr == expected_addr)); let next_addr = spks_iter.next().map(|(i, s)| { ( i, Address::from_script(s.as_script(), bitcoin::Network::Testnet) .unwrap() .to_string(), ) }); let expected_addr = "tb1qltq3nuep2fghvnytukac5mq5hxhascs0v6hm3x".to_string(); assert!(matches!(next_addr, Some((i, addr)) if i == 1 && addr == expected_addr)); }) } ```