ref(chain): move keychain::ChangeSet into txout_index.rs
				
					
				
			We plan to record `Descriptor` additions into persistence. Hence, we need to add `Descriptor`s to the changeset. This depends on `miniscript`. Moving this into `txout_index.rs` makes sense as this is consistent with all the other files. The only reason why this wasn't this way before, is because the changeset didn't need miniscript. Co-Authored-By: Daniela Brozzoni <danielabrozzoni@protonmail.com>
This commit is contained in:
		
							parent
							
								
									66abc73c3d
								
							
						
					
					
						commit
						b9902936a0
					
				| @ -320,6 +320,7 @@ impl<A, IA: Default> From<tx_graph::ChangeSet<A>> for ChangeSet<A, IA> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[cfg(feature = "miniscript")] | ||||||
| impl<A, K> From<keychain::ChangeSet<K>> for ChangeSet<A, keychain::ChangeSet<K>> { | impl<A, K> From<keychain::ChangeSet<K>> for ChangeSet<A, keychain::ChangeSet<K>> { | ||||||
|     fn from(indexer: keychain::ChangeSet<K>) -> Self { |     fn from(indexer: keychain::ChangeSet<K>) -> Self { | ||||||
|         Self { |         Self { | ||||||
|  | |||||||
| @ -10,78 +10,12 @@ | |||||||
| //!
 | //!
 | ||||||
| //! [`SpkTxOutIndex`]: crate::SpkTxOutIndex
 | //! [`SpkTxOutIndex`]: crate::SpkTxOutIndex
 | ||||||
| 
 | 
 | ||||||
| use crate::{collections::BTreeMap, Append}; |  | ||||||
| 
 |  | ||||||
| #[cfg(feature = "miniscript")] | #[cfg(feature = "miniscript")] | ||||||
| mod txout_index; | mod txout_index; | ||||||
| use bitcoin::Amount; | use bitcoin::Amount; | ||||||
| #[cfg(feature = "miniscript")] | #[cfg(feature = "miniscript")] | ||||||
| pub use txout_index::*; | pub use txout_index::*; | ||||||
| 
 | 
 | ||||||
| /// Represents updates to the derivation index of a [`KeychainTxOutIndex`].
 |  | ||||||
| /// It maps each keychain `K` to its last revealed index.
 |  | ||||||
| ///
 |  | ||||||
| /// It can be applied to [`KeychainTxOutIndex`] with [`apply_changeset`]. [`ChangeSet`]s are
 |  | ||||||
| /// monotone in that they will never decrease the revealed derivation index.
 |  | ||||||
| ///
 |  | ||||||
| /// [`KeychainTxOutIndex`]: crate::keychain::KeychainTxOutIndex
 |  | ||||||
| /// [`apply_changeset`]: crate::keychain::KeychainTxOutIndex::apply_changeset
 |  | ||||||
| #[derive(Clone, Debug, PartialEq)] |  | ||||||
| #[cfg_attr(
 |  | ||||||
|     feature = "serde", |  | ||||||
|     derive(serde::Deserialize, serde::Serialize), |  | ||||||
|     serde( |  | ||||||
|         crate = "serde_crate", |  | ||||||
|         bound( |  | ||||||
|             deserialize = "K: Ord + serde::Deserialize<'de>", |  | ||||||
|             serialize = "K: Ord + serde::Serialize" |  | ||||||
|         ) |  | ||||||
|     ) |  | ||||||
| )] |  | ||||||
| #[must_use] |  | ||||||
| pub struct ChangeSet<K>(pub BTreeMap<K, u32>); |  | ||||||
| 
 |  | ||||||
| impl<K> ChangeSet<K> { |  | ||||||
|     /// Get the inner map of the keychain to its new derivation index.
 |  | ||||||
|     pub fn as_inner(&self) -> &BTreeMap<K, u32> { |  | ||||||
|         &self.0 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K: Ord> Append for ChangeSet<K> { |  | ||||||
|     /// Append another [`ChangeSet`] into self.
 |  | ||||||
|     ///
 |  | ||||||
|     /// If the keychain already exists, increase the index when the other's index > self's index.
 |  | ||||||
|     /// If the keychain did not exist, append the new keychain.
 |  | ||||||
|     fn append(&mut self, mut other: Self) { |  | ||||||
|         self.0.iter_mut().for_each(|(key, index)| { |  | ||||||
|             if let Some(other_index) = other.0.remove(key) { |  | ||||||
|                 *index = other_index.max(*index); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|         // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`.
 |  | ||||||
|         // Refer to https://github.com/rust-lang/rust/issues/34666#issuecomment-675658420
 |  | ||||||
|         self.0.extend(other.0); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Returns whether the changeset are empty.
 |  | ||||||
|     fn is_empty(&self) -> bool { |  | ||||||
|         self.0.is_empty() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K> Default for ChangeSet<K> { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         Self(Default::default()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K> AsRef<BTreeMap<K, u32>> for ChangeSet<K> { |  | ||||||
|     fn as_ref(&self) -> &BTreeMap<K, u32> { |  | ||||||
|         &self.0 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Balance, differentiated into various categories.
 | /// Balance, differentiated into various categories.
 | ||||||
| #[derive(Debug, PartialEq, Eq, Clone, Default)] | #[derive(Debug, PartialEq, Eq, Clone, Default)] | ||||||
| #[cfg_attr(
 | #[cfg_attr(
 | ||||||
| @ -137,40 +71,3 @@ impl core::ops::Add for Balance { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #[cfg(test)] |  | ||||||
| mod test { |  | ||||||
|     use super::*; |  | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     fn append_keychain_derivation_indices() { |  | ||||||
|         #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] |  | ||||||
|         enum Keychain { |  | ||||||
|             One, |  | ||||||
|             Two, |  | ||||||
|             Three, |  | ||||||
|             Four, |  | ||||||
|         } |  | ||||||
|         let mut lhs_di = BTreeMap::<Keychain, u32>::default(); |  | ||||||
|         let mut rhs_di = BTreeMap::<Keychain, u32>::default(); |  | ||||||
|         lhs_di.insert(Keychain::One, 7); |  | ||||||
|         lhs_di.insert(Keychain::Two, 0); |  | ||||||
|         rhs_di.insert(Keychain::One, 3); |  | ||||||
|         rhs_di.insert(Keychain::Two, 5); |  | ||||||
|         lhs_di.insert(Keychain::Three, 3); |  | ||||||
|         rhs_di.insert(Keychain::Four, 4); |  | ||||||
| 
 |  | ||||||
|         let mut lhs = ChangeSet(lhs_di); |  | ||||||
|         let rhs = ChangeSet(rhs_di); |  | ||||||
|         lhs.append(rhs); |  | ||||||
| 
 |  | ||||||
|         // Exiting index doesn't update if the new index in `other` is lower than `self`.
 |  | ||||||
|         assert_eq!(lhs.0.get(&Keychain::One), Some(&7)); |  | ||||||
|         // Existing index updates if the new index in `other` is higher than `self`.
 |  | ||||||
|         assert_eq!(lhs.0.get(&Keychain::Two), Some(&5)); |  | ||||||
|         // Existing index is unchanged if keychain doesn't exist in `other`.
 |  | ||||||
|         assert_eq!(lhs.0.get(&Keychain::Three), Some(&3)); |  | ||||||
|         // New keychain gets added if the keychain is in `other` but not in `self`.
 |  | ||||||
|         assert_eq!(lhs.0.get(&Keychain::Four), Some(&4)); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -13,6 +13,71 @@ use core::{ | |||||||
| 
 | 
 | ||||||
| use crate::Append; | use crate::Append; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | /// Represents updates to the derivation index of a [`KeychainTxOutIndex`].
 | ||||||
|  | /// It maps each keychain `K` to its last revealed index.
 | ||||||
|  | ///
 | ||||||
|  | /// It can be applied to [`KeychainTxOutIndex`] with [`apply_changeset`]. [`ChangeSet] are
 | ||||||
|  | /// monotone in that they will never decrease the revealed derivation index.
 | ||||||
|  | ///
 | ||||||
|  | /// [`KeychainTxOutIndex`]: crate::keychain::KeychainTxOutIndex
 | ||||||
|  | /// [`apply_changeset`]: crate::keychain::KeychainTxOutIndex::apply_changeset
 | ||||||
|  | #[derive(Clone, Debug, PartialEq)] | ||||||
|  | #[cfg_attr(
 | ||||||
|  |     feature = "serde", | ||||||
|  |     derive(serde::Deserialize, serde::Serialize), | ||||||
|  |     serde( | ||||||
|  |         crate = "serde_crate", | ||||||
|  |         bound( | ||||||
|  |             deserialize = "K: Ord + serde::Deserialize<'de>", | ||||||
|  |             serialize = "K: Ord + serde::Serialize" | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|  | )] | ||||||
|  | #[must_use] | ||||||
|  | pub struct ChangeSet<K>(pub BTreeMap<K, u32>); | ||||||
|  | 
 | ||||||
|  | impl<K> ChangeSet<K> { | ||||||
|  |     /// Get the inner map of the keychain to its new derivation index.
 | ||||||
|  |     pub fn as_inner(&self) -> &BTreeMap<K, u32> { | ||||||
|  |         &self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K: Ord> Append for ChangeSet<K> { | ||||||
|  |     /// Append another [`ChangeSet`] into self.
 | ||||||
|  |     ///
 | ||||||
|  |     /// If the keychain already exists, increase the index when the other's index > self's index.
 | ||||||
|  |     /// If the keychain did not exist, append the new keychain.
 | ||||||
|  |     fn append(&mut self, mut other: Self) { | ||||||
|  |         self.0.iter_mut().for_each(|(key, index)| { | ||||||
|  |             if let Some(other_index) = other.0.remove(key) { | ||||||
|  |                 *index = other_index.max(*index); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`.
 | ||||||
|  |         // Refer to https://github.com/rust-lang/rust/issues/34666#issuecomment-675658420
 | ||||||
|  |         self.0.extend(other.0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Returns whether the changeset are empty.
 | ||||||
|  |     fn is_empty(&self) -> bool { | ||||||
|  |         self.0.is_empty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K> Default for ChangeSet<K> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self(Default::default()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K> AsRef<BTreeMap<K, u32>> for ChangeSet<K> { | ||||||
|  |     fn as_ref(&self) -> &BTreeMap<K, u32> { | ||||||
|  |         &self.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const DEFAULT_LOOKAHEAD: u32 = 25; | const DEFAULT_LOOKAHEAD: u32 = 25; | ||||||
| 
 | 
 | ||||||
| /// [`KeychainTxOutIndex`] controls how script pubkeys are revealed for multiple keychains, and
 | /// [`KeychainTxOutIndex`] controls how script pubkeys are revealed for multiple keychains, and
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ mod common; | |||||||
| use bdk_chain::{ | use bdk_chain::{ | ||||||
|     collections::BTreeMap, |     collections::BTreeMap, | ||||||
|     indexed_tx_graph::Indexer, |     indexed_tx_graph::Indexer, | ||||||
|     keychain::{self, KeychainTxOutIndex}, |     keychain::{self, ChangeSet, KeychainTxOutIndex}, | ||||||
|     Append, |     Append, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -44,6 +44,38 @@ fn spk_at_index(descriptor: &Descriptor<DescriptorPublicKey>, index: u32) -> Scr | |||||||
|         .script_pubkey() |         .script_pubkey() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[test] | ||||||
|  | fn append_keychain_derivation_indices() { | ||||||
|  |     #[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] | ||||||
|  |     enum Keychain { | ||||||
|  |         One, | ||||||
|  |         Two, | ||||||
|  |         Three, | ||||||
|  |         Four, | ||||||
|  |     } | ||||||
|  |     let mut lhs_di = BTreeMap::<Keychain, u32>::default(); | ||||||
|  |     let mut rhs_di = BTreeMap::<Keychain, u32>::default(); | ||||||
|  |     lhs_di.insert(Keychain::One, 7); | ||||||
|  |     lhs_di.insert(Keychain::Two, 0); | ||||||
|  |     rhs_di.insert(Keychain::One, 3); | ||||||
|  |     rhs_di.insert(Keychain::Two, 5); | ||||||
|  |     lhs_di.insert(Keychain::Three, 3); | ||||||
|  |     rhs_di.insert(Keychain::Four, 4); | ||||||
|  | 
 | ||||||
|  |     let mut lhs = ChangeSet(lhs_di); | ||||||
|  |     let rhs = ChangeSet(rhs_di); | ||||||
|  |     lhs.append(rhs); | ||||||
|  | 
 | ||||||
|  |     // Exiting index doesn't update if the new index in `other` is lower than `self`.
 | ||||||
|  |     assert_eq!(lhs.0.get(&Keychain::One), Some(&7)); | ||||||
|  |     // Existing index updates if the new index in `other` is higher than `self`.
 | ||||||
|  |     assert_eq!(lhs.0.get(&Keychain::Two), Some(&5)); | ||||||
|  |     // Existing index is unchanged if keychain doesn't exist in `other`.
 | ||||||
|  |     assert_eq!(lhs.0.get(&Keychain::Three), Some(&3)); | ||||||
|  |     // New keychain gets added if the keychain is in `other` but not in `self`.
 | ||||||
|  |     assert_eq!(lhs.0.get(&Keychain::Four), Some(&4)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_set_all_derivation_indices() { | fn test_set_all_derivation_indices() { | ||||||
|     use bdk_chain::indexed_tx_graph::Indexer; |     use bdk_chain::indexed_tx_graph::Indexer; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user