# 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));
})
}
```