[descriptor] Add support for sortedmulti in descriptor!
				
					
				
			This commit is contained in:
		
							parent
							
								
									7a42c5e095
								
							
						
					
					
						commit
						6f4d2846d3
					
				@ -27,7 +27,24 @@
 | 
				
			|||||||
#[doc(hidden)]
 | 
					#[doc(hidden)]
 | 
				
			||||||
#[macro_export]
 | 
					#[macro_export]
 | 
				
			||||||
macro_rules! impl_top_level_sh {
 | 
					macro_rules! impl_top_level_sh {
 | 
				
			||||||
    ( $descriptor_variant:ident, $( $minisc:tt )* ) => {
 | 
					    // disallow `sortedmulti` in `bare()`
 | 
				
			||||||
 | 
					    ( Bare, Bare, sortedmulti $( $inner:tt )* ) => {
 | 
				
			||||||
 | 
					        compile_error!("`bare()` descriptors can't contain any `sortedmulti` operands");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( Bare, Bare, sortedmulti_vec $( $inner:tt )* ) => {
 | 
				
			||||||
 | 
					        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec` operands");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ( $descriptor_variant:ident, $sortedmulti_variant:ident, sortedmulti $( $inner:tt )* ) => {
 | 
				
			||||||
 | 
					        $crate::impl_sortedmulti!(sortedmulti $( $inner )*)
 | 
				
			||||||
 | 
					            .and_then(|(inner, key_map, valid_networks)| Ok(($crate::miniscript::Descriptor::$sortedmulti_variant(inner), key_map, valid_networks)))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    ( $descriptor_variant:ident, $sortedmulti_variant:ident, sortedmulti_vec $( $inner:tt )* ) => {
 | 
				
			||||||
 | 
					        $crate::impl_sortedmulti!(sortedmulti_vec $( $inner )*)
 | 
				
			||||||
 | 
					            .and_then(|(inner, key_map, valid_networks)| Ok(($crate::miniscript::Descriptor::$sortedmulti_variant(inner), key_map, valid_networks)))
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ( $descriptor_variant:ident, $sortedmulti_variant:ident, $( $minisc:tt )* ) => {
 | 
				
			||||||
        $crate::fragment!($( $minisc )*)
 | 
					        $crate::fragment!($( $minisc )*)
 | 
				
			||||||
            .map(|(minisc, keymap, networks)|($crate::miniscript::Descriptor::<$crate::miniscript::descriptor::DescriptorPublicKey>::$descriptor_variant(minisc), keymap, networks))
 | 
					            .map(|(minisc, keymap, networks)|($crate::miniscript::Descriptor::<$crate::miniscript::descriptor::DescriptorPublicKey>::$descriptor_variant(minisc), keymap, networks))
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@ -160,6 +177,28 @@ macro_rules! impl_node_opcode_three {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[doc(hidden)]
 | 
				
			||||||
 | 
					#[macro_export]
 | 
				
			||||||
 | 
					macro_rules! impl_sortedmulti {
 | 
				
			||||||
 | 
					    ( sortedmulti_vec $thresh:expr, $keys:expr ) => ({
 | 
				
			||||||
 | 
					        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
 | 
				
			||||||
 | 
					        $crate::keys::make_sortedmulti_inner($thresh, $keys, &secp)
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    ( sortedmulti $thresh:expr $(, $key:expr )+ ) => ({
 | 
				
			||||||
 | 
					        use $crate::keys::ToDescriptorKey;
 | 
				
			||||||
 | 
					        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut keys = vec![];
 | 
				
			||||||
 | 
					        $(
 | 
				
			||||||
 | 
					            keys.push($key.to_descriptor_key());
 | 
				
			||||||
 | 
					        )*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        keys.into_iter().collect::<Result<Vec<_>, _>>()
 | 
				
			||||||
 | 
					            .and_then(|keys| $crate::keys::make_sortedmulti_inner($thresh, keys, &secp))
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Macro to write full descriptors with code
 | 
					/// Macro to write full descriptors with code
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This macro expands to an object of type `Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), Error>`.
 | 
					/// This macro expands to an object of type `Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), Error>`.
 | 
				
			||||||
@ -238,13 +277,13 @@ macro_rules! impl_node_opcode_three {
 | 
				
			|||||||
#[macro_export]
 | 
					#[macro_export]
 | 
				
			||||||
macro_rules! descriptor {
 | 
					macro_rules! descriptor {
 | 
				
			||||||
    ( bare ( $( $minisc:tt )* ) ) => ({
 | 
					    ( bare ( $( $minisc:tt )* ) ) => ({
 | 
				
			||||||
        $crate::impl_top_level_sh!(Bare, $( $minisc )*)
 | 
					        $crate::impl_top_level_sh!(Bare, Bare, $( $minisc )*)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => ({
 | 
					    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => ({
 | 
				
			||||||
        $crate::descriptor!(shwsh ($( $minisc )*))
 | 
					        $crate::descriptor!(shwsh ($( $minisc )*))
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    ( shwsh ( $( $minisc:tt )* ) ) => ({
 | 
					    ( shwsh ( $( $minisc:tt )* ) ) => ({
 | 
				
			||||||
        $crate::impl_top_level_sh!(ShWsh, $( $minisc )*)
 | 
					        $crate::impl_top_level_sh!(ShWsh, ShWshSortedMulti, $( $minisc )*)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    ( pk $key:expr ) => ({
 | 
					    ( pk $key:expr ) => ({
 | 
				
			||||||
        $crate::impl_top_level_pk!(Pk, $crate::miniscript::Legacy, $key)
 | 
					        $crate::impl_top_level_pk!(Pk, $crate::miniscript::Legacy, $key)
 | 
				
			||||||
@ -262,10 +301,10 @@ macro_rules! descriptor {
 | 
				
			|||||||
        $crate::impl_top_level_pk!(ShWpkh, $crate::miniscript::Segwitv0, $key)
 | 
					        $crate::impl_top_level_pk!(ShWpkh, $crate::miniscript::Segwitv0, $key)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    ( sh ( $( $minisc:tt )* ) ) => ({
 | 
					    ( sh ( $( $minisc:tt )* ) ) => ({
 | 
				
			||||||
        $crate::impl_top_level_sh!(Sh, $( $minisc )*)
 | 
					        $crate::impl_top_level_sh!(Sh, ShSortedMulti, $( $minisc )*)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    ( wsh ( $( $minisc:tt )* ) ) => ({
 | 
					    ( wsh ( $( $minisc:tt )* ) ) => ({
 | 
				
			||||||
        $crate::impl_top_level_sh!(Wsh, $( $minisc )*)
 | 
					        $crate::impl_top_level_sh!(Wsh, WshSortedMulti, $( $minisc )*)
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -404,6 +443,13 @@ macro_rules! fragment {
 | 
				
			|||||||
            .and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
 | 
					            .and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // `sortedmulti()` is handled separately
 | 
				
			||||||
 | 
					    ( sortedmulti $( $inner:tt )* ) => ({
 | 
				
			||||||
 | 
					        compile_error!("`sortedmulti` can only be used as the root operand of a descriptor");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    ( sortedmulti_vec $( $inner:tt )* ) => ({
 | 
				
			||||||
 | 
					        compile_error!("`sortedmulti_vec` can only be used as the root operand of a descriptor");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
@ -444,8 +490,8 @@ mod test {
 | 
				
			|||||||
                desc.derive(ChildNumber::from_normal_idx(index).unwrap())
 | 
					                desc.derive(ChildNumber::from_normal_idx(index).unwrap())
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            let address = child_desc.address(Regtest, deriv_ctx);
 | 
					            let address = child_desc.address(Regtest, deriv_ctx);
 | 
				
			||||||
            if address.is_some() {
 | 
					            if let Some(address) = address {
 | 
				
			||||||
                assert_eq!(address.unwrap().to_string(), *expected.get(i).unwrap());
 | 
					                assert_eq!(address.to_string(), *expected.get(i).unwrap());
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                let script = child_desc.script_pubkey(deriv_ctx);
 | 
					                let script = child_desc.script_pubkey(deriv_ctx);
 | 
				
			||||||
                assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap());
 | 
					                assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap());
 | 
				
			||||||
@ -635,6 +681,60 @@ mod test {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_dsl_sortedmulti() {
 | 
				
			||||||
 | 
					        let key_1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
 | 
				
			||||||
 | 
					        let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let key_2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
 | 
				
			||||||
 | 
					        let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let desc_key1 = (key_1, path_1);
 | 
				
			||||||
 | 
					        let desc_key2 = (key_2, path_2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check(
 | 
				
			||||||
 | 
					            descriptor!(sh(sortedmulti 1, desc_key1.clone(), desc_key2.clone())),
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            &[
 | 
				
			||||||
 | 
					                "2MsxzPEJDBzpGffJXPaDpfXZAUNnZhaMh2N",
 | 
				
			||||||
 | 
					                "2My3x3DLPK3UbGWGpxrXr1RnbD8MNC4FpgS",
 | 
				
			||||||
 | 
					                "2NByEuiQT7YLqHCTNxL5KwYjvtuCYcXNBSC",
 | 
				
			||||||
 | 
					                "2N1TGbP81kj2VUKTSWgrwxoMfuWjvfUdyu7",
 | 
				
			||||||
 | 
					                "2N3Bomq2fpAcLRNfZnD3bCWK9quan28CxCR",
 | 
				
			||||||
 | 
					                "2N9nrZaEzEFDqEAU9RPvDnXGT6AVwBDKAQb",
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check(
 | 
				
			||||||
 | 
					            descriptor!(sh(wsh(sortedmulti 1, desc_key1.clone(), desc_key2.clone()))),
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            &[
 | 
				
			||||||
 | 
					                "2NCogc5YyM4N6ruv1hUa7WLMW1BPeCK7N9B",
 | 
				
			||||||
 | 
					                "2N6mkSAKi1V2oaBXby7XHdvBMKEDRQcFpNe",
 | 
				
			||||||
 | 
					                "2NFmTSttm9v6bXeoWaBvpMcgfPQcZhNn3Eh",
 | 
				
			||||||
 | 
					                "2Mvib87RBPUHXNEpX5S5Kv1qqrhBfgBGsJM",
 | 
				
			||||||
 | 
					                "2MtMv5mcK2EjcLsH8Txpx2JxLLzHr4ttczL",
 | 
				
			||||||
 | 
					                "2MsWCB56rb4T6yPv8QudZGHERTwNgesE4f6",
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check(
 | 
				
			||||||
 | 
					            descriptor!(wsh(sortedmulti_vec 1, vec![desc_key1, desc_key2])),
 | 
				
			||||||
 | 
					            true,
 | 
				
			||||||
 | 
					            false,
 | 
				
			||||||
 | 
					            &[
 | 
				
			||||||
 | 
					                "bcrt1qcvq0lg8q7a47ytrd7zk5y7uls7mulrenjgvflwylpppgwf8029es4vhpnj",
 | 
				
			||||||
 | 
					                "bcrt1q80yn8sdt6l7pjvkz25lglyaqctlmsq9ugk80rmxt8yu0npdsj97sc7l4de",
 | 
				
			||||||
 | 
					                "bcrt1qrvf6024v9s50qhffe3t2fr2q9ckdhx2g6jz32chm2pp24ymgtr5qfrdmct",
 | 
				
			||||||
 | 
					                "bcrt1q6srfmra0ynypym35c7jvsxt2u4yrugeajq95kg2ps7lk6h2gaunsq9lzxn",
 | 
				
			||||||
 | 
					                "bcrt1qhl8rrzzcdpu7tcup3lcg7tge52sqvwy5fcv4k78v6kxtwmqf3v6qpvyjza",
 | 
				
			||||||
 | 
					                "bcrt1ql2elz9mhm9ll27ddpewhxs732xyl2fk2kpkqz9gdyh33wgcun4vstrd49k",
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
 | 
					    // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_valid_networks() {
 | 
					    fn test_valid_networks() {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ use bitcoin::{Network, PrivateKey, PublicKey};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub use miniscript::descriptor::{
 | 
					pub use miniscript::descriptor::{
 | 
				
			||||||
    DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub,
 | 
					    DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub,
 | 
				
			||||||
 | 
					    SortedMultiVec,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use miniscript::descriptor::{DescriptorXKey, KeyMap};
 | 
					use miniscript::descriptor::{DescriptorXKey, KeyMap};
 | 
				
			||||||
pub use miniscript::ScriptContext;
 | 
					pub use miniscript::ScriptContext;
 | 
				
			||||||
@ -530,6 +531,31 @@ impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> ToDescriptorKey<Ctx>
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn expand_multi_keys<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
				
			||||||
 | 
					    pks: Vec<Pk>,
 | 
				
			||||||
 | 
					    secp: &SecpCtx,
 | 
				
			||||||
 | 
					) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError> {
 | 
				
			||||||
 | 
					    let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .map(|key| Ok::<_, KeyError>(key.to_descriptor_key()?.extract(secp)?))
 | 
				
			||||||
 | 
					        .collect::<Result<Vec<_>, _>>()?
 | 
				
			||||||
 | 
					        .into_iter()
 | 
				
			||||||
 | 
					        .map(|(a, b, c)| (a, (b, c)))
 | 
				
			||||||
 | 
					        .unzip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let (key_map, valid_networks) = key_maps_networks.into_iter().fold(
 | 
				
			||||||
 | 
					        (KeyMap::default(), any_network()),
 | 
				
			||||||
 | 
					        |(mut keys_acc, net_acc), (key, net)| {
 | 
				
			||||||
 | 
					            keys_acc.extend(key.into_iter());
 | 
				
			||||||
 | 
					            let net_acc = merge_networks(&net_acc, &net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            (keys_acc, net_acc)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok((pks, key_map, valid_networks))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Used internally by `bdk::fragment!` to build `pk_k()` fragments
 | 
					// Used internally by `bdk::fragment!` to build `pk_k()` fragments
 | 
				
			||||||
#[doc(hidden)]
 | 
					#[doc(hidden)]
 | 
				
			||||||
pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
					pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
				
			||||||
@ -552,23 +578,7 @@ pub fn make_multi<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
				
			|||||||
    pks: Vec<Pk>,
 | 
					    pks: Vec<Pk>,
 | 
				
			||||||
    secp: &SecpCtx,
 | 
					    secp: &SecpCtx,
 | 
				
			||||||
) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> {
 | 
					) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> {
 | 
				
			||||||
    let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
 | 
					    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
 | 
				
			||||||
        .into_iter()
 | 
					 | 
				
			||||||
        .map(|key| Ok::<_, KeyError>(key.to_descriptor_key()?.extract(secp)?))
 | 
					 | 
				
			||||||
        .collect::<Result<Vec<_>, _>>()?
 | 
					 | 
				
			||||||
        .into_iter()
 | 
					 | 
				
			||||||
        .map(|(a, b, c)| (a, (b, c)))
 | 
					 | 
				
			||||||
        .unzip();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (key_map, valid_networks) = key_maps_networks.into_iter().fold(
 | 
					 | 
				
			||||||
        (KeyMap::default(), any_network()),
 | 
					 | 
				
			||||||
        |(mut keys_acc, net_acc), (key, net)| {
 | 
					 | 
				
			||||||
            keys_acc.extend(key.into_iter());
 | 
					 | 
				
			||||||
            let net_acc = merge_networks(&net_acc, &net);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            (keys_acc, net_acc)
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok((
 | 
					    Ok((
 | 
				
			||||||
        Miniscript::from_ast(Terminal::Multi(thresh, pks))?,
 | 
					        Miniscript::from_ast(Terminal::Multi(thresh, pks))?,
 | 
				
			||||||
@ -577,6 +587,25 @@ pub fn make_multi<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
				
			|||||||
    ))
 | 
					    ))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments
 | 
				
			||||||
 | 
					#[doc(hidden)]
 | 
				
			||||||
 | 
					pub fn make_sortedmulti_inner<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
 | 
				
			||||||
 | 
					    thresh: usize,
 | 
				
			||||||
 | 
					    pks: Vec<Pk>,
 | 
				
			||||||
 | 
					    secp: &SecpCtx,
 | 
				
			||||||
 | 
					) -> Result<
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        SortedMultiVec<DescriptorPublicKey, Ctx>,
 | 
				
			||||||
 | 
					        KeyMap,
 | 
				
			||||||
 | 
					        ValidNetworks,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    KeyError,
 | 
				
			||||||
 | 
					> {
 | 
				
			||||||
 | 
					    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok((SortedMultiVec::new(thresh, pks)?, key_map, valid_networks))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The "identity" conversion is used internally by some `bdk::fragment`s
 | 
					/// The "identity" conversion is used internally by some `bdk::fragment`s
 | 
				
			||||||
impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx> {
 | 
					impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx> {
 | 
				
			||||||
    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
 | 
					    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user