Merge bitcoindevkit/bdk-ffi#247: Add from_string() methods to DescriptorPrivateKey and DescriptorPublicKey

427816fd9a40223473eb7b7f9f1ba7fe5ea3b277 Add from_string() methods to DescriptorPrivateKey and DescriptorPublicKey (thunderbiscuit)
29614b5b7884c2571cf0085413406f9452fc81d1 Add from_string() methods to DescriptorPrivateKey and DescriptorPublicKey (thunderbiscuit)

Pull request description:

  This PR adds the `from_string()` method to the `DescriptorSecretKey` and `DescriptorPublicKey` structs.

  ### Description
  Fixes #246.

  ### Notes to the reviewers
  The error thrown is coming from rust-miniscript, so I'm not sure yet how to handle that.

  ### Changelog notice
  ```txt
  APIs Added:
    - from_string() constructors now available on DescriptorSecretKey and DescriptorPublicKey [#247]

  [#247](https://github.com/bitcoindevkit/bdk-ffi/pull/247)
  ```

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

  #### New Features:

  * [x] I've added tests for the new feature

ACKs for top commit:
  notmandatory:
    ACK 427816fd9a40223473eb7b7f9f1ba7fe5ea3b277

Tree-SHA512: a961af10549c92e1750669b148bc56c017c3929ae32199c7b71e51dca760b3dcd039ecbd68873a5175f7b02a2f1b0a94ba22018bc48d596c16d8a7d710c60fea
This commit is contained in:
Steve Myers 2022-11-29 08:59:59 -08:00
commit 8c934e9bfc
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
2 changed files with 77 additions and 23 deletions

View File

@ -304,9 +304,13 @@ interface DerivationPath {
interface DescriptorSecretKey { interface DescriptorSecretKey {
constructor(Network network, Mnemonic mnemonic, string? password); constructor(Network network, Mnemonic mnemonic, string? password);
[Name=from_string, Throws=BdkError]
constructor(string secret_key);
[Throws=BdkError] [Throws=BdkError]
DescriptorSecretKey derive(DerivationPath path); DescriptorSecretKey derive(DerivationPath path);
[Throws=BdkError]
DescriptorSecretKey extend(DerivationPath path); DescriptorSecretKey extend(DerivationPath path);
DescriptorPublicKey as_public(); DescriptorPublicKey as_public();
@ -317,9 +321,13 @@ interface DescriptorSecretKey {
}; };
interface DescriptorPublicKey { interface DescriptorPublicKey {
[Name=from_string, Throws=BdkError]
constructor(string public_key);
[Throws=BdkError] [Throws=BdkError]
DescriptorPublicKey derive(DerivationPath path); DescriptorPublicKey derive(DerivationPath path);
[Throws=BdkError]
DescriptorPublicKey extend(DerivationPath path); DescriptorPublicKey extend(DerivationPath path);
string as_string(); string as_string();

View File

@ -924,6 +924,7 @@ impl DerivationPath {
} }
} }
#[derive(Debug)]
struct DescriptorSecretKey { struct DescriptorSecretKey {
descriptor_secret_key_mutex: Mutex<BdkDescriptorSecretKey>, descriptor_secret_key_mutex: Mutex<BdkDescriptorSecretKey>,
} }
@ -943,6 +944,14 @@ impl DescriptorSecretKey {
} }
} }
fn from_string(private_key: String) -> Result<Self, BdkError> {
let descriptor_secret_key = BdkDescriptorSecretKey::from_str(private_key.as_str())
.map_err(|e| BdkError::Generic(e.to_string()))?;
Ok(Self {
descriptor_secret_key_mutex: Mutex::new(descriptor_secret_key),
})
}
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> { fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
let secp = Secp256k1::new(); let secp = Secp256k1::new();
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap(); let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
@ -964,13 +973,13 @@ impl DescriptorSecretKey {
descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key), descriptor_secret_key_mutex: Mutex::new(derived_descriptor_secret_key),
})) }))
} }
BdkDescriptorSecretKey::Single(_) => { BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
unreachable!() "Cannot derive from a single key".to_string(),
} )),
} }
} }
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> { fn extend(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap(); let descriptor_secret_key = self.descriptor_secret_key_mutex.lock().unwrap();
let path = path.derivation_path_mutex.lock().unwrap().deref().clone(); let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
match descriptor_secret_key.deref() { match descriptor_secret_key.deref() {
@ -982,13 +991,13 @@ impl DescriptorSecretKey {
derivation_path: extended_path, derivation_path: extended_path,
wildcard: descriptor_x_key.wildcard, wildcard: descriptor_x_key.wildcard,
}); });
Arc::new(Self { Ok(Arc::new(Self {
descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key), descriptor_secret_key_mutex: Mutex::new(extended_descriptor_secret_key),
}) }))
}
BdkDescriptorSecretKey::Single(_) => {
unreachable!()
} }
BdkDescriptorSecretKey::Single(_) => Err(BdkError::Generic(
"Cannot extend from a single key".to_string(),
)),
} }
} }
@ -1025,11 +1034,20 @@ impl DescriptorSecretKey {
} }
} }
#[derive(Debug)]
struct DescriptorPublicKey { struct DescriptorPublicKey {
descriptor_public_key_mutex: Mutex<BdkDescriptorPublicKey>, descriptor_public_key_mutex: Mutex<BdkDescriptorPublicKey>,
} }
impl DescriptorPublicKey { impl DescriptorPublicKey {
fn from_string(public_key: String) -> Result<Self, BdkError> {
let descriptor_public_key = BdkDescriptorPublicKey::from_str(public_key.as_str())
.map_err(|e| BdkError::Generic(e.to_string()))?;
Ok(Self {
descriptor_public_key_mutex: Mutex::new(descriptor_public_key),
})
}
fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> { fn derive(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
let secp = Secp256k1::new(); let secp = Secp256k1::new();
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap(); let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
@ -1052,13 +1070,13 @@ impl DescriptorPublicKey {
descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key), descriptor_public_key_mutex: Mutex::new(derived_descriptor_public_key),
})) }))
} }
BdkDescriptorPublicKey::Single(_) => { BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
unreachable!() "Cannot derive from a single key".to_string(),
} )),
} }
} }
fn extend(&self, path: Arc<DerivationPath>) -> Arc<Self> { fn extend(&self, path: Arc<DerivationPath>) -> Result<Arc<Self>, BdkError> {
let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap(); let descriptor_public_key = self.descriptor_public_key_mutex.lock().unwrap();
let path = path.derivation_path_mutex.lock().unwrap().deref().clone(); let path = path.derivation_path_mutex.lock().unwrap().deref().clone();
match descriptor_public_key.deref() { match descriptor_public_key.deref() {
@ -1070,13 +1088,13 @@ impl DescriptorPublicKey {
derivation_path: extended_path, derivation_path: extended_path,
wildcard: descriptor_x_key.wildcard, wildcard: descriptor_x_key.wildcard,
}); });
Arc::new(Self { Ok(Arc::new(Self {
descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key), descriptor_public_key_mutex: Mutex::new(extended_descriptor_public_key),
}) }))
}
BdkDescriptorPublicKey::Single(_) => {
unreachable!()
} }
BdkDescriptorPublicKey::Single(_) => Err(BdkError::Generic(
"Cannot extend from a single key".to_string(),
)),
} }
} }
@ -1176,7 +1194,10 @@ mod test {
key.derive(path) key.derive(path)
} }
fn extend_dsk(key: &DescriptorSecretKey, path: &str) -> Arc<DescriptorSecretKey> { fn extend_dsk(
key: &DescriptorSecretKey,
path: &str,
) -> Result<Arc<DescriptorSecretKey>, BdkError> {
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap()); let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
key.extend(path) key.extend(path)
} }
@ -1189,7 +1210,10 @@ mod test {
key.derive(path) key.derive(path)
} }
fn extend_dpk(key: &DescriptorPublicKey, path: &str) -> Arc<DescriptorPublicKey> { fn extend_dpk(
key: &DescriptorPublicKey,
path: &str,
) -> Result<Arc<DescriptorPublicKey>, BdkError> {
let path = Arc::new(DerivationPath::new(path.to_string()).unwrap()); let path = Arc::new(DerivationPath::new(path.to_string()).unwrap());
key.extend(path) key.extend(path)
} }
@ -1226,12 +1250,34 @@ mod test {
#[test] #[test]
fn test_extend_descriptor_keys() { fn test_extend_descriptor_keys() {
let master_dsk = get_descriptor_secret_key(); let master_dsk = get_descriptor_secret_key();
let extended_dsk: &DescriptorSecretKey = &extend_dsk(&master_dsk, "m/0"); let extended_dsk: &DescriptorSecretKey = &extend_dsk(&master_dsk, "m/0").unwrap();
assert_eq!(extended_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/*"); assert_eq!(extended_dsk.as_string(), "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/*");
let master_dpk: &DescriptorPublicKey = &master_dsk.as_public(); let master_dpk: &DescriptorPublicKey = &master_dsk.as_public();
let extended_dpk: &DescriptorPublicKey = &extend_dpk(master_dpk, "m/0"); let extended_dpk: &DescriptorPublicKey = &extend_dpk(master_dpk, "m/0").unwrap();
assert_eq!(extended_dpk.as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/*"); assert_eq!(extended_dpk.as_string(), "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/*");
let wif = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch";
let extended_key = DescriptorSecretKey::from_string(wif.to_string()).unwrap();
let result = extended_key.derive(Arc::new(DerivationPath::new("m/0".to_string()).unwrap()));
dbg!(&result);
assert!(result.is_err());
}
#[test]
fn test_from_str_descriptor_secret_key() {
let key1 = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch";
let key2 = "tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/1/1/*";
let private_descriptor_key1 = DescriptorSecretKey::from_string(key1.to_string()).unwrap();
let private_descriptor_key2 = DescriptorSecretKey::from_string(key2.to_string()).unwrap();
dbg!(private_descriptor_key1);
dbg!(private_descriptor_key2);
// Should error out because you can't produce a DescriptorSecretKey from an xpub
let key0 = "tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi";
assert!(DescriptorSecretKey::from_string(key0.to_string()).is_err());
} }
#[test] #[test]
@ -1242,7 +1288,7 @@ mod test {
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*"); assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
// extend derived_dsk with path "m/0" // extend derived_dsk with path "m/0"
let extended_dsk: &DescriptorSecretKey = &extend_dsk(derived_dsk, "m/0"); let extended_dsk: &DescriptorSecretKey = &extend_dsk(derived_dsk, "m/0").unwrap();
assert_eq!(extended_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/*"); assert_eq!(extended_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/*");
} }