From 5c2bbfb7a69bda99fec289edc8545da9a59caff8 Mon Sep 17 00:00:00 2001 From: thunderbiscuit Date: Wed, 27 Sep 2023 13:38:07 -0400 Subject: [PATCH] Temp 11: Add Descriptor and Mnemonic types --- README.md | 6 + bdk-ffi/src/bdk.udl | 38 ++ bdk-ffi/src/descriptor.rs | 503 ++++++++++-------- bdk-ffi/src/lib.rs | 2 + bdk-ffi/src/wallet.rs | 28 +- bdk-ffi/tests/README.md | 13 +- .../kotlin/org/bitcoindevkit/JvmLibTest.kt | 12 +- .../bitcoindevkit/plugins/UniFfiJvmPlugin.kt | 6 +- 8 files changed, 354 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 8a461af2..1e0753bb 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,12 @@ cargo update -p hashlink --precise "0.8.1" cargo update -p tokio --precise "1.29.1" # flate2 1.0.27 and up do not work with Rust 1.61.0, but 1.0.26 does cargo update -p flate2 --precise "1.0.26" +# clap 4.4.4 has MSRV 1.70, so we must keep it at 4.4.3 +cargo update -p clap --precise 4.4.3 +# anstyle 1.0.3 has MSRV 1.70.0, so we must keep it at 1.0.2 +cargo update -p anstyle --precise 1.0.2 +cargo update -p clap_builder --precise 4.4.1 +cargo update -p clap_lex --precise 0.5.1 ``` ## Contributing diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index 3ea1b16b..537a92e8 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -93,3 +93,41 @@ interface DescriptorPublicKey { string as_string(); }; + +enum KeychainKind { + "External", + "Internal", +}; + +interface Descriptor { + [Throws=BdkError] + constructor(string descriptor, Network network); + + [Name=new_bip44] + constructor(DescriptorSecretKey secret_key, KeychainKind keychain, Network network); + + [Name=new_bip44_public] + constructor(DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network); + + [Name=new_bip49] + constructor(DescriptorSecretKey secret_key, KeychainKind keychain, Network network); + + [Name=new_bip49_public] + constructor(DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network); + + [Name=new_bip84] + constructor(DescriptorSecretKey secret_key, KeychainKind keychain, Network network); + + [Name=new_bip84_public] + constructor(DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network); + + [Name=new_bip86] + constructor(DescriptorSecretKey secret_key, KeychainKind keychain, Network network); + + [Name=new_bip86_public] + constructor(DescriptorPublicKey public_key, string fingerprint, KeychainKind keychain, Network network); + + string as_string(); + + string as_string_private(); +}; diff --git a/bdk-ffi/src/descriptor.rs b/bdk-ffi/src/descriptor.rs index 39144a5d..d8336d98 100644 --- a/bdk-ffi/src/descriptor.rs +++ b/bdk-ffi/src/descriptor.rs @@ -2,7 +2,6 @@ // use bdk::bitcoin::secp256k1::Secp256k1; // use bdk::bitcoin::util::bip32::Fingerprint; // use bdk::bitcoin::Network; -// use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor, KeyMap}; // use bdk::keys::{ // DescriptorPublicKey as BdkDescriptorPublicKey, DescriptorSecretKey as BdkDescriptorSecretKey, // }; @@ -13,238 +12,276 @@ // use bdk::KeychainKind; // use std::str::FromStr; // use std::sync::Arc; -// -// #[derive(Debug)] -// pub(crate) struct Descriptor { -// pub(crate) extended_descriptor: ExtendedDescriptor, -// pub(crate) key_map: KeyMap, -// } -// -// impl Descriptor { -// pub(crate) fn new(descriptor: String, network: Network) -> Result { -// let secp = Secp256k1::new(); -// let (extended_descriptor, key_map) = descriptor.into_wallet_descriptor(&secp, network)?; -// Ok(Self { -// extended_descriptor, -// key_map, -// }) -// } -// -// pub(crate) fn new_bip44( -// secret_key: Arc, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let derivable_key = &secret_key.inner; -// -// match derivable_key { -// BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip44(derivable_key, keychain_kind).build(network).unwrap(); -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorSecretKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip44_public( -// public_key: Arc, -// fingerprint: String, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); -// let derivable_key = &public_key.inner; -// -// match derivable_key { -// BdkDescriptorPublicKey::XPub(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip44Public(derivable_key, fingerprint, keychain_kind) -// .build(network) -// .unwrap(); -// -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorPublicKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip49( -// secret_key: Arc, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let derivable_key = &secret_key.inner; -// -// match derivable_key { -// BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip49(derivable_key, keychain_kind).build(network).unwrap(); -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorSecretKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip49_public( -// public_key: Arc, -// fingerprint: String, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); -// let derivable_key = &public_key.inner; -// -// match derivable_key { -// BdkDescriptorPublicKey::XPub(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip49Public(derivable_key, fingerprint, keychain_kind) -// .build(network) -// .unwrap(); -// -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorPublicKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip84( -// secret_key: Arc, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let derivable_key = &secret_key.inner; -// -// match derivable_key { -// BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip84(derivable_key, keychain_kind).build(network).unwrap(); -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorSecretKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip84_public( -// public_key: Arc, -// fingerprint: String, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); -// let derivable_key = &public_key.inner; -// -// match derivable_key { -// BdkDescriptorPublicKey::XPub(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip84Public(derivable_key, fingerprint, keychain_kind) -// .build(network) -// .unwrap(); -// -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorPublicKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip86( -// secret_key: Arc, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let derivable_key = &secret_key.inner; -// -// match derivable_key { -// BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip86(derivable_key, keychain_kind).build(network).unwrap(); -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorSecretKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn new_bip86_public( -// public_key: Arc, -// fingerprint: String, -// keychain_kind: KeychainKind, -// network: Network, -// ) -> Self { -// let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); -// let derivable_key = &public_key.inner; -// -// match derivable_key { -// BdkDescriptorPublicKey::XPub(descriptor_x_key) => { -// let derivable_key = descriptor_x_key.xkey; -// let (extended_descriptor, key_map, _) = -// Bip86Public(derivable_key, fingerprint, keychain_kind) -// .build(network) -// .unwrap(); -// -// Self { -// extended_descriptor, -// key_map, -// } -// } -// BdkDescriptorPublicKey::Single(_) => { -// unreachable!() -// } -// } -// } -// -// pub(crate) fn as_string_private(&self) -> String { -// let descriptor = &self.extended_descriptor; -// let key_map = &self.key_map; -// descriptor.to_string_with_secret(key_map) -// } -// -// pub(crate) fn as_string(&self) -> String { -// self.extended_descriptor.to_string() -// } -// } -// + +use std::str::FromStr; +use std::sync::Arc; +use bdk::bitcoin::key::Secp256k1; +use bdk::descriptor::{ExtendedDescriptor, IntoWalletDescriptor}; +use bdk::keys::{DescriptorSecretKey as BdkDescriptorSecretKey, KeyMap}; +use bdk::keys::DescriptorPublicKey as BdkDescriptorPublicKey; +use bdk::{Error as BdkError}; +use bdk::bitcoin::bip32::Fingerprint; +use bdk::KeychainKind; +use bdk::template::{Bip44, Bip44Public, Bip49, Bip49Public, Bip84, Bip84Public, Bip86, Bip86Public, DescriptorTemplate}; + +use crate::keys::DescriptorSecretKey; +use crate::keys::DescriptorPublicKey; +use crate::Network; + +#[derive(Debug)] +pub(crate) struct Descriptor { + pub extended_descriptor: ExtendedDescriptor, + pub key_map: KeyMap, +} + +impl Descriptor { + pub(crate) fn new(descriptor: String, network: Network) -> Result { + let secp = Secp256k1::new(); + let (extended_descriptor, key_map) = descriptor.into_wallet_descriptor(&secp, network.into())?; + Ok(Self { + extended_descriptor, + key_map, + }) + } + + pub(crate) fn new_bip44( + secret_key: Arc, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let derivable_key = &secret_key.inner; + + match derivable_key { + BdkDescriptorSecretKey::Single(_) => { + unreachable!() + } + BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = Bip44(derivable_key, keychain_kind).build(network.into()).unwrap(); + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorSecretKey::MultiXPrv(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip44_public( + public_key: Arc, + fingerprint: String, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); + let derivable_key = &public_key.inner; + + match derivable_key { + BdkDescriptorPublicKey::Single(_) => { + unreachable!() + } + BdkDescriptorPublicKey::XPub(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip44Public(derivable_key, fingerprint, keychain_kind) + .build(network.into()) + .unwrap(); + + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorPublicKey::MultiXPub(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip49( + secret_key: Arc, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let derivable_key = &secret_key.inner; + + match derivable_key { + BdkDescriptorSecretKey::Single(_) => { + unreachable!() + } + BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip49(derivable_key, keychain_kind).build(network.into()).unwrap(); + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorSecretKey::MultiXPrv(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip49_public( + public_key: Arc, + fingerprint: String, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); + let derivable_key = &public_key.inner; + + match derivable_key { + BdkDescriptorPublicKey::Single(_) => { + unreachable!() + } + BdkDescriptorPublicKey::XPub(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip49Public(derivable_key, fingerprint, keychain_kind) + .build(network.into()) + .unwrap(); + + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorPublicKey::MultiXPub(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip84( + secret_key: Arc, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let derivable_key = &secret_key.inner; + + match derivable_key { + BdkDescriptorSecretKey::Single(_) => { + unreachable!() + } + BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip84(derivable_key, keychain_kind).build(network.into()).unwrap(); + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorSecretKey::MultiXPrv(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip84_public( + public_key: Arc, + fingerprint: String, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); + let derivable_key = &public_key.inner; + + match derivable_key { + BdkDescriptorPublicKey::Single(_) => { + unreachable!() + } + BdkDescriptorPublicKey::XPub(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip84Public(derivable_key, fingerprint, keychain_kind) + .build(network.into()) + .unwrap(); + + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorPublicKey::MultiXPub(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip86( + secret_key: Arc, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let derivable_key = &secret_key.inner; + + match derivable_key { + BdkDescriptorSecretKey::Single(_) => { + unreachable!() + } + BdkDescriptorSecretKey::XPrv(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip86(derivable_key, keychain_kind).build(network.into()).unwrap(); + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorSecretKey::MultiXPrv(_) => { + unreachable!() + } + } + } + + pub(crate) fn new_bip86_public( + public_key: Arc, + fingerprint: String, + keychain_kind: KeychainKind, + network: Network, + ) -> Self { + let fingerprint = Fingerprint::from_str(fingerprint.as_str()).unwrap(); + let derivable_key = &public_key.inner; + + match derivable_key { + BdkDescriptorPublicKey::Single(_) => { + unreachable!() + } + BdkDescriptorPublicKey::XPub(descriptor_x_key) => { + let derivable_key = descriptor_x_key.xkey; + let (extended_descriptor, key_map, _) = + Bip86Public(derivable_key, fingerprint, keychain_kind) + .build(network.into()) + .unwrap(); + + Self { + extended_descriptor, + key_map, + } + } + BdkDescriptorPublicKey::MultiXPub(_) => { + unreachable!() + } + } + } + + pub(crate) fn as_string_private(&self) -> String { + let descriptor = &self.extended_descriptor; + let key_map = &self.key_map; + descriptor.to_string_with_secret(key_map) + } + + pub(crate) fn as_string(&self) -> String { + self.extended_descriptor.to_string() + } +} + // // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs. // // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk` // // crate. diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 4f36c76d..b5cc71b6 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -54,6 +54,8 @@ use bdk::keys::bip39::WordCount; use crate::keys::Mnemonic; use crate::keys::DescriptorPublicKey; use crate::keys::DescriptorSecretKey; +use bdk::KeychainKind; +use crate::descriptor::Descriptor; uniffi::include_scaffolding!("bdk"); diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs index 35253ccf..efe4f48f 100644 --- a/bdk-ffi/src/wallet.rs +++ b/bdk-ffi/src/wallet.rs @@ -27,21 +27,37 @@ // AddressIndex, AddressInfo, Balance, BdkError, LocalUtxo, OutPoint, Progress, ProgressHolder, // RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult, // }; -// + +use bdk::Wallet as BdkWallet; +// use bdk::Error as BdkError; // pub fn hello_world() -> String { // String::from("Hello World") // } -// #[derive(Debug)] -// pub(crate) struct Wallet { -// pub(crate) inner: BdkWallet, -// } -// + +#[derive(Debug)] +pub(crate) struct Wallet { + pub(crate) inner: BdkWallet, +} + // /// A Bitcoin wallet. // /// The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are: // /// 1. Output descriptors from which it can derive addresses. // /// 2. A Database where it tracks transactions and utxos related to the descriptors. // /// 3. Signers that can contribute signatures to addresses instantiated from the descriptors. +// impl Wallet { +// pub fn new( +// descriptor: Arc, +// change_descriptor: Option>, +// network: Network, +// ) -> Result { +// let wallet = BdkWallet::new_no_persist()?; +// Ok(Wallet { +// inner: wallet, +// }) +// } +// } + // impl Wallet { // // pub(crate) fn new( // // descriptor: Arc, diff --git a/bdk-ffi/tests/README.md b/bdk-ffi/tests/README.md index 9d7c154d..faaaf449 100644 --- a/bdk-ffi/tests/README.md +++ b/bdk-ffi/tests/README.md @@ -9,13 +9,12 @@ To run all tests including integration tests use `CLASSPATH=./tests/jna/jna-5.8. Before running integration tests you must install the following development tools: -1. [Java](https://openjdk.org/) and [Kotlin](https://kotlinlang.org/), -[sdkman](https://sdkman.io/) can help: - ```shell - sdk install java 11.0.16.1-zulu - sdk install kotlin 1.7.20` - ``` - +1. [Java](https://openjdk.org/) and [Kotlin](https://kotlinlang.org/), [sdkman](https://sdkman.io/) can help: +```shell +sdk install java 11.0.16.1-zulu +sdk install kotlin 1.7.20 +``` + 2. [Swift](https://www.swift.org/) 3. [Python](https://www.python.org/) diff --git a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/JvmLibTest.kt b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/JvmLibTest.kt index 0613b22c..4d66e059 100644 --- a/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/JvmLibTest.kt +++ b/bdk-jvm/lib/src/test/kotlin/org/bitcoindevkit/JvmLibTest.kt @@ -6,18 +6,18 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.File import java.nio.file.Files -import org.bitcoindevkit.helloWorld class JvmLibTest { @Test - fun testHelloWorld() { - val message = helloWorld() - assertEquals("Hello World", message) + fun testNetwork() { + val signetNetwork = Network.SIGNET } @Test - fun testNetwork() { - val signetNetwork = Network.SIGNET + fun testDescriptorBip86() { + val mnemonic = Mnemonic(WordCount.WORDS12) + val descriptorSecretKey = DescriptorSecretKey(Network.TESTNET, mnemonic, null) + val descriptor = Descriptor.newBip86(descriptorSecretKey, KeychainKind.EXTERNAL, Network.TESTNET) } } /** diff --git a/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt b/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt index 253ec82c..e0753637 100644 --- a/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt +++ b/bdk-jvm/plugins/src/main/kotlin/org/bitcoindevkit/plugins/UniFfiJvmPlugin.kt @@ -8,6 +8,8 @@ import org.gradle.kotlin.dsl.getValue import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.register +// TODO #1: Migrate hard coded strings to constants all in the same location so they're at least easy +// to find and reason about. internal class UniFfiJvmPlugin : Plugin { override fun apply(target: Project): Unit = target.run { @@ -108,8 +110,8 @@ internal class UniFfiJvmPlugin : Plugin { dependsOn(moveNativeJvmLibs) - // TODO: Is the Windows name the correct one? - // TODO: This will not work on mac Intel (x86_64 architecture) + // TODO 2: Is the Windows name the correct one? + // TODO 3: This will not work on mac Intel (x86_64 architecture) val libraryPath = when (operatingSystem) { OS.LINUX -> "./target/x86_64-unknown-linux-gnu/release-smaller/libbdkffi.so" OS.MAC -> "./target/aarch64-apple-darwin/release-smaller/libbdkffi.dylib"