Skip to content

Commit 4ae1229

Browse files
committed
Remove hashbrown dependency
We can use `BTreeSet` instead of `HashSet` and `BTreeMap` instead of `HashMap` to remove the `hashbrown` dependency. For traits implemented on `HashMap` feature guard them on "std" and implement them on `BTreeMap`. Requires some pretty funky macros so we don't have to duplicate code.
1 parent 1f7f575 commit 4ae1229

File tree

6 files changed

+112
-67
lines changed

6 files changed

+112
-67
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ edition = "2018"
1313
[features]
1414
default = ["std"]
1515
std = ["bitcoin/std", "bitcoin/secp-recovery"]
16-
no-std = ["hashbrown", "bitcoin/no-std"]
16+
no-std = ["bitcoin/no-std"]
1717
compiler = []
1818
trace = []
1919

@@ -24,7 +24,6 @@ base64 = ["bitcoin/base64"]
2424

2525
[dependencies]
2626
bitcoin = { version = "0.30.0", default-features = false }
27-
hashbrown = { version = "0.11", optional = true }
2827
internals = { package = "bitcoin-private", version = "0.1.0", default_features = false }
2928

3029
# Do NOT use this as a feature! Use the `serde` feature instead.

src/descriptor/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub use self::key::{
5757
/// [`Descriptor::parse_descriptor`], since the descriptor will always only contain
5858
/// public keys. This map allows looking up the corresponding secret key given a
5959
/// public key from the descriptor.
60-
pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey>;
60+
pub type KeyMap = BTreeMap<DescriptorPublicKey, DescriptorSecretKey>;
6161

6262
/// Script descriptor
6363
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -658,7 +658,7 @@ impl Descriptor<DescriptorPublicKey> {
658658
Ok(public_key)
659659
}
660660

661-
let mut keymap_pk = KeyMapWrapper(HashMap::new(), secp);
661+
let mut keymap_pk = KeyMapWrapper(BTreeMap::new(), secp);
662662

663663
struct KeyMapWrapper<'a, C: secp256k1::Signing>(KeyMap, &'a secp256k1::Secp256k1<C>);
664664

src/lib.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,6 @@ pub use bitcoin;
9999
#[macro_use]
100100
extern crate alloc;
101101

102-
#[cfg(not(feature = "std"))]
103-
extern crate hashbrown;
104-
105102
#[cfg(any(feature = "std", test))]
106103
extern crate core;
107104

@@ -972,9 +969,6 @@ mod prelude {
972969
vec::Vec,
973970
};
974971

975-
#[cfg(all(not(feature = "std"), not(test)))]
976-
pub use hashbrown::{HashMap, HashSet};
977-
978972
#[cfg(all(not(feature = "std"), not(test)))]
979973
pub use self::mutex::Mutex;
980974
}

src/miniscript/analyzable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
214214
// to have an iterator
215215
let all_pkhs_len = self.iter_pk().count();
216216

217-
let unique_pkhs_len = self.iter_pk().collect::<HashSet<_>>().len();
217+
let unique_pkhs_len = self.iter_pk().collect::<BTreeSet<_>>().len();
218218

219219
unique_pkhs_len != all_pkhs_len
220220
}

src/miniscript/satisfy.rs

Lines changed: 107 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -154,72 +154,124 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for absolute::LockTime {
154154
}
155155
}
156156
}
157-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for HashMap<Pk, bitcoin::ecdsa::Signature> {
158-
fn lookup_ecdsa_sig(&self, key: &Pk) -> Option<bitcoin::ecdsa::Signature> {
159-
self.get(key).copied()
160-
}
161-
}
162157

163-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
164-
for HashMap<(Pk, TapLeafHash), bitcoin::taproot::Signature>
165-
{
166-
fn lookup_tap_leaf_script_sig(
167-
&self,
168-
key: &Pk,
169-
h: &TapLeafHash,
170-
) -> Option<bitcoin::taproot::Signature> {
171-
// Unfortunately, there is no way to get a &(a, b) from &a and &b without allocating
172-
// If we change the signature the of lookup_tap_leaf_script_sig to accept a tuple. We would
173-
// face the same problem while satisfying PkK.
174-
// We use this signature to optimize for the psbt common use case.
175-
self.get(&(key.clone(), *h)).copied()
158+
// You can ignore the complexity of this and similar macros below, all they do is implement
159+
// `Satisfier` on both `BTreeMap` and `HashMap` feature guarding the `HashMap` impl on "std"
160+
// feature.
161+
macro_rules! impl_satisfier_for_map_key_to_ecdsa_sig {
162+
($($(#[cfg($attr:meta)])* $map:ident),*) => {
163+
$(
164+
$(#[cfg($attr)])*
165+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for $map<Pk, bitcoin::ecdsa::Signature> {
166+
fn lookup_ecdsa_sig(&self, key: &Pk) -> Option<bitcoin::ecdsa::Signature> {
167+
self.get(key).copied()
168+
}
169+
}
170+
)*
176171
}
177172
}
178-
179-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
180-
for HashMap<hash160::Hash, (Pk, bitcoin::ecdsa::Signature)>
181-
where
182-
Pk: MiniscriptKey + ToPublicKey,
183-
{
184-
fn lookup_ecdsa_sig(&self, key: &Pk) -> Option<bitcoin::ecdsa::Signature> {
185-
self.get(&key.to_pubkeyhash(SigType::Ecdsa)).map(|x| x.1)
173+
impl_satisfier_for_map_key_to_ecdsa_sig!(
174+
BTreeMap,
175+
#[cfg(feature = "std")]
176+
HashMap
177+
);
178+
179+
macro_rules! impl_satisfier_for_map_key_hash_to_taproot_sig {
180+
($($(#[cfg($attr:meta)])* $map:ident),*) => {
181+
$(
182+
$(#[cfg($attr)])*
183+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
184+
for $map<(Pk, TapLeafHash), bitcoin::taproot::Signature>
185+
{
186+
fn lookup_tap_leaf_script_sig(
187+
&self,
188+
key: &Pk,
189+
h: &TapLeafHash,
190+
) -> Option<bitcoin::taproot::Signature> {
191+
// Unfortunately, there is no way to get a &(a, b) from &a and &b without allocating
192+
// If we change the signature the of lookup_tap_leaf_script_sig to accept a tuple. We would
193+
// face the same problem while satisfying PkK.
194+
// We use this signature to optimize for the psbt common use case.
195+
self.get(&(key.clone(), *h)).copied()
196+
}
197+
}
198+
)*
186199
}
200+
}
201+
impl_satisfier_for_map_key_hash_to_taproot_sig!(
202+
BTreeMap,
203+
#[cfg(feature = "std")]
204+
HashMap
205+
);
206+
207+
macro_rules! impl_satisfier_for_map_hash_to_key_ecdsa_sig {
208+
($($(#[cfg($attr:meta)])* $map:ident),*) => {
209+
$(
210+
$(#[cfg($attr)])*
211+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
212+
for $map<hash160::Hash, (Pk, bitcoin::ecdsa::Signature)>
213+
where
214+
Pk: MiniscriptKey + ToPublicKey,
215+
{
216+
fn lookup_ecdsa_sig(&self, key: &Pk) -> Option<bitcoin::ecdsa::Signature> {
217+
self.get(&key.to_pubkeyhash(SigType::Ecdsa)).map(|x| x.1)
218+
}
187219

188-
fn lookup_raw_pkh_pk(&self, pk_hash: &hash160::Hash) -> Option<bitcoin::PublicKey> {
189-
self.get(pk_hash).map(|x| x.0.to_public_key())
190-
}
220+
fn lookup_raw_pkh_pk(&self, pk_hash: &hash160::Hash) -> Option<bitcoin::PublicKey> {
221+
self.get(pk_hash).map(|x| x.0.to_public_key())
222+
}
191223

192-
fn lookup_raw_pkh_ecdsa_sig(
193-
&self,
194-
pk_hash: &hash160::Hash,
195-
) -> Option<(bitcoin::PublicKey, bitcoin::ecdsa::Signature)> {
196-
self.get(pk_hash)
197-
.map(|&(ref pk, sig)| (pk.to_public_key(), sig))
224+
fn lookup_raw_pkh_ecdsa_sig(
225+
&self,
226+
pk_hash: &hash160::Hash,
227+
) -> Option<(bitcoin::PublicKey, bitcoin::ecdsa::Signature)> {
228+
self.get(pk_hash)
229+
.map(|&(ref pk, sig)| (pk.to_public_key(), sig))
230+
}
231+
}
232+
)*
198233
}
199234
}
235+
impl_satisfier_for_map_hash_to_key_ecdsa_sig!(
236+
BTreeMap,
237+
#[cfg(feature = "std")]
238+
HashMap
239+
);
240+
241+
macro_rules! impl_satisfier_for_map_hash_tapleafhash_to_key_taproot_sig {
242+
($($(#[cfg($attr:meta)])* $map:ident),*) => {
243+
$(
244+
$(#[cfg($attr)])*
245+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
246+
for $map<(hash160::Hash, TapLeafHash), (Pk, bitcoin::taproot::Signature)>
247+
where
248+
Pk: MiniscriptKey + ToPublicKey,
249+
{
250+
fn lookup_tap_leaf_script_sig(
251+
&self,
252+
key: &Pk,
253+
h: &TapLeafHash,
254+
) -> Option<bitcoin::taproot::Signature> {
255+
self.get(&(key.to_pubkeyhash(SigType::Schnorr), *h))
256+
.map(|x| x.1)
257+
}
200258

201-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk>
202-
for HashMap<(hash160::Hash, TapLeafHash), (Pk, bitcoin::taproot::Signature)>
203-
where
204-
Pk: MiniscriptKey + ToPublicKey,
205-
{
206-
fn lookup_tap_leaf_script_sig(
207-
&self,
208-
key: &Pk,
209-
h: &TapLeafHash,
210-
) -> Option<bitcoin::taproot::Signature> {
211-
self.get(&(key.to_pubkeyhash(SigType::Schnorr), *h))
212-
.map(|x| x.1)
213-
}
214-
215-
fn lookup_raw_pkh_tap_leaf_script_sig(
216-
&self,
217-
pk_hash: &(hash160::Hash, TapLeafHash),
218-
) -> Option<(XOnlyPublicKey, bitcoin::taproot::Signature)> {
219-
self.get(pk_hash)
220-
.map(|&(ref pk, sig)| (pk.to_x_only_pubkey(), sig))
259+
fn lookup_raw_pkh_tap_leaf_script_sig(
260+
&self,
261+
pk_hash: &(hash160::Hash, TapLeafHash),
262+
) -> Option<(XOnlyPublicKey, bitcoin::taproot::Signature)> {
263+
self.get(pk_hash)
264+
.map(|&(ref pk, sig)| (pk.to_x_only_pubkey(), sig))
265+
}
266+
}
267+
)*
221268
}
222269
}
270+
impl_satisfier_for_map_hash_tapleafhash_to_key_taproot_sig!(
271+
BTreeMap,
272+
#[cfg(feature = "std")]
273+
HashMap
274+
);
223275

224276
impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'a S {
225277
fn lookup_ecdsa_sig(&self, p: &Pk) -> Option<bitcoin::ecdsa::Signature> {

src/policy/concrete.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
840840
pub fn check_duplicate_keys(&self) -> Result<(), PolicyError> {
841841
let pks = self.keys();
842842
let pks_len = pks.len();
843-
let unique_pks_len = pks.into_iter().collect::<HashSet<_>>().len();
843+
let unique_pks_len = pks.into_iter().collect::<BTreeSet<_>>().len();
844844

845845
if pks_len > unique_pks_len {
846846
Err(PolicyError::DuplicatePubKeys)

0 commit comments

Comments
 (0)