Skip to content

Commit

Permalink
Make bdk no_std
Browse files Browse the repository at this point in the history
  • Loading branch information
LLFourn committed Jan 10, 2023
1 parent b4f421a commit a8291b8
Show file tree
Hide file tree
Showing 21 changed files with 144 additions and 106 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ getrandom = "0.2"
js-sys = "0.3"

[features]
default = ["std"]
std = []
compiler = ["miniscript/compiler"]
all-keys = ["keys-bip39"]
keys-bip39 = ["bip39"]
Expand Down Expand Up @@ -64,6 +66,7 @@ required-features = ["compiler"]
[[example]]
name = "policy"
path = "examples/policy.rs"
required-features = ["std"]

[[example]]
name = "mnemonic_to_descriptors"
Expand Down
4 changes: 2 additions & 2 deletions bdk_test_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use bitcoin::{Address, PackedLockTime, Script, Sequence, Transaction, Txid, Witn
pub use bitcoincore_rpc::bitcoincore_rpc_json::AddressType;
use bitcoincore_rpc::jsonrpc::serde_json::{self, json};
pub use bitcoincore_rpc::{Auth, Client as RpcClient, Error as RpcError, RpcApi};
use core::ops::Deref;
use core::str::FromStr;
use core::time::Duration;
use electrsd::bitcoind::BitcoinD;
use electrsd::{bitcoind, ElectrsD};
pub use electrum_client::{Client as ElectrumClient, ElectrumApi};
#[allow(unused_imports)]
use log::{debug, error, info, log_enabled, trace, Level};
use std::env;
use std::ops::Deref;
use std::time::Duration;

pub struct TestClient {
pub bitcoind: BitcoinD,
Expand Down
3 changes: 2 additions & 1 deletion src/descriptor/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//! checksum of a descriptor

use crate::descriptor::DescriptorError;
use alloc::string::String;

const INPUT_CHARSET: &[u8] = b"0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
const CHECKSUM_CHARSET: &[u8] = b"qpzry9x8gf2tvdw0s3jn54khce6mua7l";
Expand Down Expand Up @@ -170,7 +171,7 @@ mod test {

#[test]
fn test_calc_checksum_invalid_character() {
let sparkle_heart = unsafe { std::str::from_utf8_unchecked(&[240, 159, 146, 150]) };
let sparkle_heart = unsafe { core::str::from_utf8_unchecked(&[240, 159, 146, 150]) };
let invalid_desc = format!("wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcL{}fjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)", sparkle_heart);

assert_matches!(
Expand Down
45 changes: 23 additions & 22 deletions src/descriptor/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ macro_rules! impl_top_level_sh {
};

( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti $( $inner:tt )* ) => {{
use std::marker::PhantomData;
use core::marker::PhantomData;

use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
use $crate::miniscript::$ctx;
Expand All @@ -35,7 +35,7 @@ macro_rules! impl_top_level_sh {
$crate::impl_sortedmulti!(build_desc, sortedmulti $( $inner )*)
}};
( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti_vec $( $inner:tt )* ) => {{
use std::marker::PhantomData;
use core::marker::PhantomData;

use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
use $crate::miniscript::$ctx;
Expand Down Expand Up @@ -203,8 +203,8 @@ macro_rules! impl_node_opcode_two {
a_keymap.extend(b_keymap.into_iter());

let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
std::sync::Arc::new(a_minisc),
std::sync::Arc::new(b_minisc),
alloc::sync::Arc::new(a_minisc),
alloc::sync::Arc::new(b_minisc),
))?;

minisc.check_miniscript()?;
Expand Down Expand Up @@ -234,9 +234,9 @@ macro_rules! impl_node_opcode_three {
let networks = $crate::keys::merge_networks(&networks, &c_networks);

let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
std::sync::Arc::new(a_minisc),
std::sync::Arc::new(b_minisc),
std::sync::Arc::new(c_minisc),
alloc::sync::Arc::new(a_minisc),
alloc::sync::Arc::new(b_minisc),
alloc::sync::Arc::new(c_minisc),
))?;

minisc.check_miniscript()?;
Expand All @@ -263,7 +263,7 @@ macro_rules! impl_sortedmulti {
)*
];

keys.into_iter().collect::<Result<Vec<_>, _>>()
keys.into_iter().collect::<Result<alloc::vec::Vec<_>, _>>()
.map_err($crate::descriptor::DescriptorError::Key)
.and_then(|keys| $crate::keys::make_sortedmulti($thresh, keys, $build_desc, &secp))
});
Expand All @@ -274,7 +274,7 @@ macro_rules! impl_sortedmulti {
#[macro_export]
macro_rules! parse_tap_tree {
( @merge $tree_a:expr, $tree_b:expr) => {{
use std::sync::Arc;
use alloc::sync::Arc;
use $crate::miniscript::descriptor::TapTree;

$tree_a
Expand Down Expand Up @@ -318,7 +318,7 @@ macro_rules! parse_tap_tree {

// Single leaf
( $op:ident ( $( $minisc:tt )* ) ) => {{
use std::sync::Arc;
use alloc::sync::Arc;
use $crate::miniscript::descriptor::TapTree;

$crate::fragment!( $op ( $( $minisc )* ) )
Expand All @@ -337,7 +337,7 @@ macro_rules! apply_modifier {
.and_then(|(minisc, keymap, networks)| {
let minisc = $crate::miniscript::Miniscript::from_ast(
$crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
std::sync::Arc::new(minisc),
alloc::sync::Arc::new(minisc),
),
)?;

Expand Down Expand Up @@ -374,8 +374,8 @@ macro_rules! apply_modifier {
$inner.and_then(|(a_minisc, a_keymap, a_networks)| {
$crate::impl_leaf_opcode_value_two!(
AndV,
std::sync::Arc::new(a_minisc),
std::sync::Arc::new($crate::fragment!(true).unwrap().0)
alloc::sync::Arc::new(a_minisc),
alloc::sync::Arc::new($crate::fragment!(true).unwrap().0)
)
.map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
})
Expand All @@ -384,8 +384,8 @@ macro_rules! apply_modifier {
$inner.and_then(|(a_minisc, a_keymap, a_networks)| {
$crate::impl_leaf_opcode_value_two!(
OrI,
std::sync::Arc::new($crate::fragment!(false).unwrap().0),
std::sync::Arc::new(a_minisc)
alloc::sync::Arc::new($crate::fragment!(false).unwrap().0),
alloc::sync::Arc::new(a_minisc)
)
.map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
})
Expand All @@ -394,8 +394,8 @@ macro_rules! apply_modifier {
$inner.and_then(|(a_minisc, a_keymap, a_networks)| {
$crate::impl_leaf_opcode_value_two!(
OrI,
std::sync::Arc::new(a_minisc),
std::sync::Arc::new($crate::fragment!(false).unwrap().0)
alloc::sync::Arc::new(a_minisc),
alloc::sync::Arc::new($crate::fragment!(false).unwrap().0)
)
.map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
})
Expand Down Expand Up @@ -599,7 +599,7 @@ macro_rules! group_multi_keys {
)*
];

keys.into_iter().collect::<Result<Vec<_>, _>>()
keys.into_iter().collect::<Result<alloc::vec::Vec<_>, _>>()
.map_err($crate::descriptor::DescriptorError::Key)
}};
}
Expand Down Expand Up @@ -744,8 +744,8 @@ macro_rules! fragment {
( thresh_vec ( $thresh:expr, $items:expr ) ) => ({
use $crate::miniscript::descriptor::KeyMap;

let (items, key_maps_networks): (Vec<_>, Vec<_>) = $items.into_iter().map(|(a, b, c)| (a, (b, c))).unzip();
let items = items.into_iter().map(std::sync::Arc::new).collect();
let (items, key_maps_networks): (alloc::vec::Vec<_>, alloc::vec::Vec<_>) = $items.into_iter().map(|(a, b, c)| (a, (b, c))).unzip();
let items = items.into_iter().map(alloc::sync::Arc::new).collect();

let (key_maps, valid_networks) = key_maps_networks.into_iter().fold((KeyMap::default(), $crate::keys::any_network()), |(mut keys_acc, net_acc), (key, net)| {
keys_acc.extend(key.into_iter());
Expand All @@ -760,7 +760,7 @@ macro_rules! fragment {
( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
let items = $crate::fragment_internal!( @v $( $inner )* );

items.into_iter().collect::<Result<Vec<_>, _>>()
items.into_iter().collect::<Result<alloc::vec::Vec<_>, _>>()
.and_then(|items| $crate::fragment!(thresh_vec($thresh, items)))
});
( multi_vec ( $thresh:expr, $keys:expr ) ) => ({
Expand Down Expand Up @@ -793,12 +793,13 @@ macro_rules! fragment {

#[cfg(test)]
mod test {
use alloc::string::ToString;
use bitcoin::hashes::hex::ToHex;
use bitcoin::secp256k1::Secp256k1;
use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
use miniscript::{Descriptor, Legacy, Segwitv0};

use std::str::FromStr;
use core::str::FromStr;

use crate::descriptor::{DescriptorError, DescriptorMeta};
use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
Expand Down
5 changes: 3 additions & 2 deletions src/descriptor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ impl From<crate::keys::KeyError> for Error {
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

impl_error!(bitcoin::util::bip32::Error, Bip32);
Expand Down
7 changes: 5 additions & 2 deletions src/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
//! This module contains generic utilities to work with descriptors, plus some re-exported types
//! from [`miniscript`].

use std::collections::BTreeMap;
use crate::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;

use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
use bitcoin::util::{psbt, taproot};
Expand Down Expand Up @@ -581,7 +583,8 @@ impl DescriptorMeta for ExtendedDescriptor {

#[cfg(test)]
mod test {
use std::str::FromStr;
use alloc::string::ToString;
use core::str::FromStr;

use assert_matches::assert_matches;
use bitcoin::consensus::encode::deserialize;
Expand Down
29 changes: 16 additions & 13 deletions src/descriptor/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
//! # Ok::<(), bdk::Error>(())
//! ```

use std::cmp::max;
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::fmt;
use crate::collections::{BTreeMap, HashSet, VecDeque};
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp::max;
use core::fmt;

use serde::ser::SerializeMap;
use serde::{Serialize, Serializer};
Expand Down Expand Up @@ -516,6 +518,7 @@ impl fmt::Display for PolicyError {
}
}

#[cfg(feature = "std")]
impl std::error::Error for PolicyError {}

impl Policy {
Expand Down Expand Up @@ -1139,12 +1142,12 @@ mod test {
use crate::descriptor::policy::SatisfiableItem::{EcdsaSignature, Multisig, Thresh};
use crate::keys::{DescriptorKey, IntoDescriptorKey};
use crate::wallet::signer::SignersContainer;
use alloc::{string::ToString, sync::Arc};
use assert_matches::assert_matches;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::util::bip32;
use bitcoin::Network;
use std::str::FromStr;
use std::sync::Arc;
use core::str::FromStr;

const TPRV0_STR:&str = "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf";
const TPRV1_STR:&str = "tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N";
Expand Down Expand Up @@ -1437,12 +1440,12 @@ mod test {
.into_wallet_descriptor(&secp, Network::Testnet)
.unwrap();
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
let policy = wallet_desc
let _policy = wallet_desc
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
.unwrap()
.unwrap();
println!("desc policy = {:?}", policy); // TODO remove
// TODO how should this fail with mixed timelocks?
// println!("desc policy = {:?}", policy); // TODO remove
// TODO how should this fail with mixed timelocks?
}

// - multiple timelocks of the same type should be correctly merged together
Expand All @@ -1462,12 +1465,12 @@ mod test {
.into_wallet_descriptor(&secp, Network::Testnet)
.unwrap();
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
let policy = wallet_desc
let _policy = wallet_desc
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
.unwrap()
.unwrap();
println!("desc policy = {:?}", policy); // TODO remove
// TODO how should this merge timelocks?
// println!("desc policy = {:?}", policy); // TODO remove
// TODO how should this merge timelocks?
let (prvkey1, _pubkey1, _fingerprint1) = setup_keys(TPRV0_STR, PATH, &secp);
let locktime_seconds0 = 500000100;
let locktime_seconds1 = 500000200;
Expand All @@ -1480,12 +1483,12 @@ mod test {
.into_wallet_descriptor(&secp, Network::Testnet)
.unwrap();
let signers_container = Arc::new(SignersContainer::build(keymap, &wallet_desc, &secp));
let policy = wallet_desc
let _policy = wallet_desc
.extract_policy(&signers_container, BuildSatisfaction::None, &secp)
.unwrap()
.unwrap();

println!("desc policy = {:?}", policy); // TODO remove
// println!("desc policy = {:?}", policy); // TODO remove

// TODO how should this merge timelocks?
}
Expand Down
5 changes: 3 additions & 2 deletions src/descriptor/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ macro_rules! expand_make_bipxx {
keychain: KeychainKind,
network: Network,
) -> Result<impl IntoDescriptorKey<$ctx>, DescriptorError> {
let mut derivation_path = Vec::with_capacity(4);
let mut derivation_path = alloc::vec::Vec::with_capacity(4);
derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);

match network {
Expand Down Expand Up @@ -478,7 +478,8 @@ expand_make_bipxx!(segwit_v0, Segwitv0);
mod test {
// test existing descriptor templates, make sure they are expanded to the right descriptors

use std::str::FromStr;
use alloc::{string::ToString, vec::Vec};
use core::str::FromStr;

use super::*;
use crate::descriptor::{DescriptorError, DescriptorMeta};
Expand Down
7 changes: 4 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
// You may not use this file except in accordance with one or both of these
// licenses.

use std::fmt;

use crate::bitcoin::Network;
use crate::{descriptor, wallet};
use alloc::{string::String, vec::Vec};
use bitcoin::{OutPoint, Txid};
use core::fmt;

/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
#[derive(Debug)]
Expand Down Expand Up @@ -151,14 +151,15 @@ impl fmt::Display for Error {
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

macro_rules! impl_error {
( $from:ty, $to:ident ) => {
impl_error!($from, $to, Error);
};
( $from:ty, $to:ident, $impl_for:ty ) => {
impl std::convert::From<$from> for $impl_for {
impl core::convert::From<$from> for $impl_for {
fn from(err: $from) -> Self {
<$impl_for>::$to(err)
}
Expand Down
4 changes: 3 additions & 1 deletion src/keys/bip39.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// TODO: maybe write our own implementation of bip39? Seems stupid to have an extra dependency for
// something that should be fairly simple to re-implement.

use alloc::string::String;
use bitcoin::util::bip32;
use bitcoin::Network;

Expand Down Expand Up @@ -150,7 +151,8 @@ impl<Ctx: ScriptContext> GeneratableKey<Ctx> for Mnemonic {

#[cfg(test)]
mod test {
use std::str::FromStr;
use alloc::string::ToString;
use core::str::FromStr;

use bitcoin::util::bip32;

Expand Down
Loading

0 comments on commit a8291b8

Please sign in to comment.