pub trait IntoDescriptorKey<Ctx: ScriptContext>: Sized {
    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
}
Expand description

Trait for objects that can be turned into a public or secret DescriptorKey

The generic type Ctx is used to define the context in which the key is valid: some key formats, like the mnemonics used by Electrum wallets, encode internally whether the wallet is legacy or segwit. Thus, trying to turn a valid legacy mnemonic into a DescriptorKey that would become part of a segwit descriptor should fail.

For key types that do care about this, the ExtScriptContext trait provides some useful methods that can be used to check at runtime which Ctx is being used.

For key types that can do this check statically (because they can only work within a single Ctx), the “specialized” trait can be implemented to make the compiler handle the type checking.

Keys also have control over the networks they support: constructing the return object with DescriptorKey::from_public or DescriptorKey::from_secret allows to specify a set of ValidNetworks.

Examples

Key type valid in any context:

use bdk::bitcoin::PublicKey;

use bdk::keys::{DescriptorKey, IntoDescriptorKey, KeyError, ScriptContext};

pub struct MyKeyType {
    pubkey: PublicKey,
}

impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
        self.pubkey.into_descriptor_key()
    }
}

Key type that is only valid on mainnet:

use bdk::bitcoin::PublicKey;

use bdk::keys::{
    mainnet_network, DescriptorKey, DescriptorPublicKey, IntoDescriptorKey, KeyError,
    ScriptContext, SinglePub, SinglePubKey,
};

pub struct MyKeyType {
    pubkey: PublicKey,
}

impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
        Ok(DescriptorKey::from_public(
            DescriptorPublicKey::Single(SinglePub {
                origin: None,
                key: SinglePubKey::FullKey(self.pubkey),
            }),
            mainnet_network(),
        ))
    }
}

Key type that internally encodes in which context it’s valid. The context is checked at runtime:

use bdk::bitcoin::PublicKey;

use bdk::keys::{DescriptorKey, ExtScriptContext, IntoDescriptorKey, KeyError, ScriptContext};

pub struct MyKeyType {
    is_legacy: bool,
    pubkey: PublicKey,
}

impl<Ctx: ScriptContext + 'static> IntoDescriptorKey<Ctx> for MyKeyType {
    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
        if Ctx::is_legacy() == self.is_legacy {
            self.pubkey.into_descriptor_key()
        } else {
            Err(KeyError::InvalidScriptContext)
        }
    }
}

Key type that can only work within miniscript::Segwitv0 context. Only the specialized version of the trait is implemented.

This example deliberately fails to compile, to demonstrate how the compiler can catch when keys are misused. In this case, the “segwit-only” key is used to build a pkh() descriptor, which makes the compiler (correctly) fail.

use bdk::bitcoin::PublicKey;
use core::str::FromStr;

use bdk::keys::{DescriptorKey, IntoDescriptorKey, KeyError};

pub struct MySegwitOnlyKeyType {
    pubkey: PublicKey,
}

impl IntoDescriptorKey<bdk::miniscript::Segwitv0> for MySegwitOnlyKeyType {
    fn into_descriptor_key(self) -> Result<DescriptorKey<bdk::miniscript::Segwitv0>, KeyError> {
        self.pubkey.into_descriptor_key()
    }
}

let key = MySegwitOnlyKeyType {
    pubkey: PublicKey::from_str("...")?,
};
let (descriptor, _, _) = bdk::descriptor!(pkh(key))?;
//                                       ^^^^^ changing this to `wpkh` would make it compile

Required Methods§

Turn the key into a DescriptorKey within the requested ScriptContext

Implementations on Foreign Types§

Implementors§

The “identity” conversion is used internally by some bdk::fragments