Merge bitcoindevkit/bdk#1229: Use a universal lookahead value for KeychainTxOutIndex and have a reasonable default
				
					
				
			1def76f1f17fc876534c798883099c58de57c0fd chore: make clippy happy and bump clippy msrv (志宇) c9467dcbb27bd497006846dcfcefb0c2cf8823c4 chore: improve documentation of lookahead (LLFourn) bc796f412acdc3d2cd96f7aec0f24fa47c1fe889 fix(example): bitcoind_rpc_polling now initializes local_chain properly (志宇) 4fd539b6470f7f771e3b5e09e3287952fa7a1825 feat(chain)!: `KeychainTxOutIndex` uses a universal lookahead (Antoine Poinsot) Pull request description: ### Description The `bdk::Wallet` is currently created without setting any lookahead value for the keychain. This implicitly makes it a lookahead of 0. As this is a high-level interface we should avoid footguns and aim for a reasonable default. To fix this, we have also decided to change `KeychainTxOutIndex` to have a default lookahead. Additionally, we have simplified the `KeychainTxOutIndex` API to have a single `lookahead` that is ONLY set at construction `KeychainTxOutIndex::new(lookahead: u32) -> Self`. This avoids the footguns of having methods which allows the caller to decrease the `lookahead` (which will panic). ### Notes to the reviewers ~A way to set this value externally is introduced in #1172. This PR only aims to use a saner default than 0. `1_000` is the value used by the Bitcoin Core wallet, and that seems reasonable to me.~ Edit: we should NOT allow setting the `lookahead` value after-the-fact. Instead, the `lookahead` should be provided to the wallet's constructor. @evanlinjin: I don't think additional tests are necessary as no additional features are added, and the surface area of the API is decreased. The original tests already thoroughly test the `lookahead` concept. ### Checklists #### All Submissions: *(This section was updated as this PR changed from being a simple setting to introducing a new method.)* * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing ~* [ ] I've added tests~ * [x] I've added docs ACKs for top commit: LLFourn: ACK 1def76f1f17fc876534c798883099c58de57c0fd Tree-SHA512: b4c3be8a4f2ac4877cf3f05852147e7dd1daeb02d3bc40895f02fd2a58e584f1dc0735b524153ff0875380ac93c0b4c31e516873d7a9b0027fdbbb5fe7970ff2
This commit is contained in:
		
						commit
						7eff024213
					
				
							
								
								
									
										2
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							| @ -118,7 +118,7 @@ jobs: | |||||||
|       - uses: actions/checkout@v1 |       - uses: actions/checkout@v1 | ||||||
|       - uses: actions-rs/toolchain@v1 |       - uses: actions-rs/toolchain@v1 | ||||||
|         with: |         with: | ||||||
|             toolchain: "stable" |             toolchain: stable | ||||||
|             components: clippy |             components: clippy | ||||||
|             override: true |             override: true | ||||||
|       - name: Rust Cache |       - name: Rust Cache | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| msrv="1.57.0" | msrv="1.63.0" | ||||||
|  | |||||||
| @ -575,7 +575,7 @@ mod test { | |||||||
| 
 | 
 | ||||||
|         if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 { |         if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 { | ||||||
|             let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into(); |             let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into(); | ||||||
|             let purpose = path.get(0).unwrap(); |             let purpose = path.first().unwrap(); | ||||||
|             assert_matches!(purpose, Hardened { index: 44 }); |             assert_matches!(purpose, Hardened { index: 44 }); | ||||||
|             let coin_type = path.get(1).unwrap(); |             let coin_type = path.get(1).unwrap(); | ||||||
|             assert_matches!(coin_type, Hardened { index: 0 }); |             assert_matches!(coin_type, Hardened { index: 0 }); | ||||||
| @ -589,7 +589,7 @@ mod test { | |||||||
| 
 | 
 | ||||||
|         if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 { |         if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 { | ||||||
|             let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into(); |             let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into(); | ||||||
|             let purpose = path.get(0).unwrap(); |             let purpose = path.first().unwrap(); | ||||||
|             assert_matches!(purpose, Hardened { index: 44 }); |             assert_matches!(purpose, Hardened { index: 44 }); | ||||||
|             let coin_type = path.get(1).unwrap(); |             let coin_type = path.get(1).unwrap(); | ||||||
|             assert_matches!(coin_type, Hardened { index: 1 }); |             assert_matches!(coin_type, Hardened { index: 1 }); | ||||||
|  | |||||||
| @ -812,9 +812,10 @@ pub struct SignOptions { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Customize which taproot script-path leaves the signer should sign.
 | /// Customize which taproot script-path leaves the signer should sign.
 | ||||||
| #[derive(Debug, Clone, PartialEq, Eq)] | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||||||
| pub enum TapLeavesOptions { | pub enum TapLeavesOptions { | ||||||
|     /// The signer will sign all the leaves it has a key for.
 |     /// The signer will sign all the leaves it has a key for.
 | ||||||
|  |     #[default] | ||||||
|     All, |     All, | ||||||
|     /// The signer won't sign leaves other than the ones specified. Note that it could still ignore
 |     /// The signer won't sign leaves other than the ones specified. Note that it could still ignore
 | ||||||
|     /// some of the specified leaves, if it doesn't have the right key to sign them.
 |     /// some of the specified leaves, if it doesn't have the right key to sign them.
 | ||||||
| @ -825,12 +826,6 @@ pub enum TapLeavesOptions { | |||||||
|     None, |     None, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for TapLeavesOptions { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         TapLeavesOptions::All |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[allow(clippy::derivable_impls)] | #[allow(clippy::derivable_impls)] | ||||||
| impl Default for SignOptions { | impl Default for SignOptions { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|  | |||||||
| @ -811,9 +811,10 @@ impl<'a, D> TxBuilder<'a, D, DefaultCoinSelectionAlgorithm, BumpFee> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Ordering of the transaction's inputs and outputs
 | /// Ordering of the transaction's inputs and outputs
 | ||||||
| #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] | #[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] | ||||||
| pub enum TxOrdering { | pub enum TxOrdering { | ||||||
|     /// Randomized (default)
 |     /// Randomized (default)
 | ||||||
|  |     #[default] | ||||||
|     Shuffle, |     Shuffle, | ||||||
|     /// Unchanged
 |     /// Unchanged
 | ||||||
|     Untouched, |     Untouched, | ||||||
| @ -821,12 +822,6 @@ pub enum TxOrdering { | |||||||
|     Bip69Lexicographic, |     Bip69Lexicographic, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for TxOrdering { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         TxOrdering::Shuffle |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl TxOrdering { | impl TxOrdering { | ||||||
|     /// Sort transaction inputs and outputs by [`TxOrdering`] variant
 |     /// Sort transaction inputs and outputs by [`TxOrdering`] variant
 | ||||||
|     pub fn sort_tx(&self, tx: &mut Transaction) { |     pub fn sort_tx(&self, tx: &mut Transaction) { | ||||||
| @ -880,9 +875,10 @@ impl RbfValue { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Policy regarding the use of change outputs when creating a transaction
 | /// Policy regarding the use of change outputs when creating a transaction
 | ||||||
| #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] | #[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] | ||||||
| pub enum ChangeSpendPolicy { | pub enum ChangeSpendPolicy { | ||||||
|     /// Use both change and non-change outputs (default)
 |     /// Use both change and non-change outputs (default)
 | ||||||
|  |     #[default] | ||||||
|     ChangeAllowed, |     ChangeAllowed, | ||||||
|     /// Only use change outputs (see [`TxBuilder::only_spend_change`])
 |     /// Only use change outputs (see [`TxBuilder::only_spend_change`])
 | ||||||
|     OnlyChange, |     OnlyChange, | ||||||
| @ -890,12 +886,6 @@ pub enum ChangeSpendPolicy { | |||||||
|     ChangeForbidden, |     ChangeForbidden, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for ChangeSpendPolicy { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         ChangeSpendPolicy::ChangeAllowed |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl ChangeSpendPolicy { | impl ChangeSpendPolicy { | ||||||
|     pub(crate) fn is_satisfied_by(&self, utxo: &LocalOutput) -> bool { |     pub(crate) fn is_satisfied_by(&self, utxo: &LocalOutput) -> bool { | ||||||
|         match self { |         match self { | ||||||
|  | |||||||
| @ -5,12 +5,13 @@ use crate::{ | |||||||
|     spk_iter::BIP32_MAX_INDEX, |     spk_iter::BIP32_MAX_INDEX, | ||||||
|     SpkIterator, SpkTxOutIndex, |     SpkIterator, SpkTxOutIndex, | ||||||
| }; | }; | ||||||
| use alloc::vec::Vec; |  | ||||||
| use bitcoin::{OutPoint, Script, TxOut}; | use bitcoin::{OutPoint, Script, TxOut}; | ||||||
| use core::{fmt::Debug, ops::Deref}; | use core::{fmt::Debug, ops::Deref}; | ||||||
| 
 | 
 | ||||||
| use crate::Append; | use crate::Append; | ||||||
| 
 | 
 | ||||||
|  | const DEFAULT_LOOKAHEAD: u32 = 1_000; | ||||||
|  | 
 | ||||||
| /// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
 | /// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
 | ||||||
| /// [`Descriptor`]s.
 | /// [`Descriptor`]s.
 | ||||||
| ///
 | ///
 | ||||||
| @ -46,7 +47,7 @@ use crate::Append; | |||||||
| /// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | /// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | ||||||
| /// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | /// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | ||||||
| /// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
 | /// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
 | ||||||
| /// # let descriptor_for_user_42 = external_descriptor.clone();
 | /// # let (descriptor_for_user_42, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/2/*)").unwrap();
 | ||||||
| /// txout_index.add_keychain(MyKeychain::External, external_descriptor);
 | /// txout_index.add_keychain(MyKeychain::External, external_descriptor);
 | ||||||
| /// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
 | /// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
 | ||||||
| /// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
 | /// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
 | ||||||
| @ -65,17 +66,12 @@ pub struct KeychainTxOutIndex<K> { | |||||||
|     // last revealed indexes
 |     // last revealed indexes
 | ||||||
|     last_revealed: BTreeMap<K, u32>, |     last_revealed: BTreeMap<K, u32>, | ||||||
|     // lookahead settings for each keychain
 |     // lookahead settings for each keychain
 | ||||||
|     lookahead: BTreeMap<K, u32>, |     lookahead: u32, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<K> Default for KeychainTxOutIndex<K> { | impl<K> Default for KeychainTxOutIndex<K> { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         Self { |         Self::new(DEFAULT_LOOKAHEAD) | ||||||
|             inner: SpkTxOutIndex::default(), |  | ||||||
|             keychains: BTreeMap::default(), |  | ||||||
|             last_revealed: BTreeMap::default(), |  | ||||||
|             lookahead: BTreeMap::default(), |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -118,6 +114,25 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<K> KeychainTxOutIndex<K> { | ||||||
|  |     /// Construct a [`KeychainTxOutIndex`] with the given `lookahead`.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The `lookahead` is the number of script pubkeys to derive and cache from the internal
 | ||||||
|  |     /// descriptors over and above the last revealed script index. Without a lookahead the index
 | ||||||
|  |     /// will miss outputs you own when processing transactions whose output script pubkeys lie
 | ||||||
|  |     /// beyond the last revealed index. In certain situations, such as when performing an initial
 | ||||||
|  |     /// scan of the blockchain during wallet import, it may be uncertain or unknown what the index
 | ||||||
|  |     /// of the last revealed script pubkey actually is.
 | ||||||
|  |     pub fn new(lookahead: u32) -> Self { | ||||||
|  |         Self { | ||||||
|  |             inner: SpkTxOutIndex::default(), | ||||||
|  |             keychains: BTreeMap::new(), | ||||||
|  |             last_revealed: BTreeMap::new(), | ||||||
|  |             lookahead, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | ||||||
|     /// Return a reference to the internal [`SpkTxOutIndex`].
 |     /// Return a reference to the internal [`SpkTxOutIndex`].
 | ||||||
|     pub fn inner(&self) -> &SpkTxOutIndex<(K, u32)> { |     pub fn inner(&self) -> &SpkTxOutIndex<(K, u32)> { | ||||||
| @ -145,54 +160,22 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | |||||||
|     pub fn add_keychain(&mut self, keychain: K, descriptor: Descriptor<DescriptorPublicKey>) { |     pub fn add_keychain(&mut self, keychain: K, descriptor: Descriptor<DescriptorPublicKey>) { | ||||||
|         let old_descriptor = &*self |         let old_descriptor = &*self | ||||||
|             .keychains |             .keychains | ||||||
|             .entry(keychain) |             .entry(keychain.clone()) | ||||||
|             .or_insert_with(|| descriptor.clone()); |             .or_insert_with(|| descriptor.clone()); | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             &descriptor, old_descriptor, |             &descriptor, old_descriptor, | ||||||
|             "keychain already contains a different descriptor" |             "keychain already contains a different descriptor" | ||||||
|         ); |         ); | ||||||
|  |         self.replenish_lookahead(&keychain, self.lookahead); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Return the lookahead setting for each keychain.
 |     /// Get the lookahead setting.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// Refer to [`set_lookahead`] for a deeper explanation of the `lookahead`.
 |     /// Refer to [`new`] for more information on the `lookahead`.
 | ||||||
|     ///
 |     ///
 | ||||||
|     /// [`set_lookahead`]: Self::set_lookahead
 |     /// [`new`]: Self::new
 | ||||||
|     pub fn lookaheads(&self) -> &BTreeMap<K, u32> { |     pub fn lookahead(&self) -> u32 { | ||||||
|         &self.lookahead |         self.lookahead | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Convenience method to call [`set_lookahead`] for all keychains.
 |  | ||||||
|     ///
 |  | ||||||
|     /// [`set_lookahead`]: Self::set_lookahead
 |  | ||||||
|     pub fn set_lookahead_for_all(&mut self, lookahead: u32) { |  | ||||||
|         for keychain in &self.keychains.keys().cloned().collect::<Vec<_>>() { |  | ||||||
|             self.set_lookahead(keychain, lookahead); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Set the lookahead count for `keychain`.
 |  | ||||||
|     ///
 |  | ||||||
|     /// The lookahead is the number of scripts to cache ahead of the last revealed script index. This
 |  | ||||||
|     /// is useful to find outputs you own when processing block data that lie beyond the last revealed
 |  | ||||||
|     /// index. In certain situations, such as when performing an initial scan of the blockchain during
 |  | ||||||
|     /// wallet import, it may be uncertain or unknown what the last revealed index is.
 |  | ||||||
|     ///
 |  | ||||||
|     /// # Panics
 |  | ||||||
|     ///
 |  | ||||||
|     /// This will panic if the `keychain` does not exist.
 |  | ||||||
|     pub fn set_lookahead(&mut self, keychain: &K, lookahead: u32) { |  | ||||||
|         self.lookahead.insert(keychain.clone(), lookahead); |  | ||||||
|         self.replenish_lookahead(keychain); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Convenience method to call [`lookahead_to_target`] for multiple keychains.
 |  | ||||||
|     ///
 |  | ||||||
|     /// [`lookahead_to_target`]: Self::lookahead_to_target
 |  | ||||||
|     pub fn lookahead_to_target_multi(&mut self, target_indexes: BTreeMap<K, u32>) { |  | ||||||
|         for (keychain, target_index) in target_indexes { |  | ||||||
|             self.lookahead_to_target(&keychain, target_index) |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Store lookahead scripts until `target_index`.
 |     /// Store lookahead scripts until `target_index`.
 | ||||||
| @ -201,22 +184,14 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | |||||||
|     pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) { |     pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) { | ||||||
|         let next_index = self.next_store_index(keychain); |         let next_index = self.next_store_index(keychain); | ||||||
|         if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) { |         if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) { | ||||||
|             let old_lookahead = self.lookahead.insert(keychain.clone(), temp_lookahead); |             self.replenish_lookahead(keychain, temp_lookahead); | ||||||
|             self.replenish_lookahead(keychain); |  | ||||||
| 
 |  | ||||||
|             // revert
 |  | ||||||
|             match old_lookahead { |  | ||||||
|                 Some(lookahead) => self.lookahead.insert(keychain.clone(), lookahead), |  | ||||||
|                 None => self.lookahead.remove(keychain), |  | ||||||
|             }; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn replenish_lookahead(&mut self, keychain: &K) { |     fn replenish_lookahead(&mut self, keychain: &K, lookahead: u32) { | ||||||
|         let descriptor = self.keychains.get(keychain).expect("keychain must exist"); |         let descriptor = self.keychains.get(keychain).expect("keychain must exist"); | ||||||
|         let next_store_index = self.next_store_index(keychain); |         let next_store_index = self.next_store_index(keychain); | ||||||
|         let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1); |         let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1); | ||||||
|         let lookahead = self.lookahead.get(keychain).map_or(0, |v| *v); |  | ||||||
| 
 | 
 | ||||||
|         for (new_index, new_spk) in |         for (new_index, new_spk) in | ||||||
|             SpkIterator::new_with_range(descriptor, next_store_index..next_reveal_index + lookahead) |             SpkIterator::new_with_range(descriptor, next_store_index..next_reveal_index + lookahead) | ||||||
| @ -388,12 +363,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | |||||||
| 
 | 
 | ||||||
|         let target_index = if has_wildcard { target_index } else { 0 }; |         let target_index = if has_wildcard { target_index } else { 0 }; | ||||||
|         let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1); |         let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1); | ||||||
|         let lookahead = self.lookahead.get(keychain).map_or(0, |v| *v); |  | ||||||
| 
 | 
 | ||||||
|         debug_assert_eq!( |         debug_assert!(next_reveal_index + self.lookahead >= self.next_store_index(keychain)); | ||||||
|             next_reveal_index + lookahead, |  | ||||||
|             self.next_store_index(keychain) |  | ||||||
|         ); |  | ||||||
| 
 | 
 | ||||||
|         // if we need to reveal new indices, the latest revealed index goes here
 |         // if we need to reveal new indices, the latest revealed index goes here
 | ||||||
|         let mut reveal_to_index = None; |         let mut reveal_to_index = None; | ||||||
| @ -401,12 +372,12 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> { | |||||||
|         // if the target is not yet revealed, but is already stored (due to lookahead), we need to
 |         // if the target is not yet revealed, but is already stored (due to lookahead), we need to
 | ||||||
|         // set the `reveal_to_index` as target here (as the `for` loop below only updates
 |         // set the `reveal_to_index` as target here (as the `for` loop below only updates
 | ||||||
|         // `reveal_to_index` for indexes that are NOT stored)
 |         // `reveal_to_index` for indexes that are NOT stored)
 | ||||||
|         if next_reveal_index <= target_index && target_index < next_reveal_index + lookahead { |         if next_reveal_index <= target_index && target_index < next_reveal_index + self.lookahead { | ||||||
|             reveal_to_index = Some(target_index); |             reveal_to_index = Some(target_index); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // we range over indexes that are not stored
 |         // we range over indexes that are not stored
 | ||||||
|         let range = next_reveal_index + lookahead..=target_index + lookahead; |         let range = next_reveal_index + self.lookahead..=target_index + self.lookahead; | ||||||
|         for (new_index, new_spk) in SpkIterator::new_with_range(descriptor, range) { |         for (new_index, new_spk) in SpkIterator::new_with_range(descriptor, range) { | ||||||
|             let _inserted = self |             let _inserted = self | ||||||
|                 .inner |                 .inner | ||||||
|  | |||||||
| @ -148,7 +148,7 @@ mod test { | |||||||
|         Descriptor<DescriptorPublicKey>, |         Descriptor<DescriptorPublicKey>, | ||||||
|         Descriptor<DescriptorPublicKey>, |         Descriptor<DescriptorPublicKey>, | ||||||
|     ) { |     ) { | ||||||
|         let mut txout_index = KeychainTxOutIndex::<TestKeychain>::default(); |         let mut txout_index = KeychainTxOutIndex::<TestKeychain>::new(0); | ||||||
| 
 | 
 | ||||||
|         let secp = Secp256k1::signing_only(); |         let secp = Secp256k1::signing_only(); | ||||||
|         let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap(); |         let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap(); | ||||||
|  | |||||||
| @ -168,9 +168,7 @@ impl<I: Clone + Ord> SpkTxOutIndex<I> { | |||||||
|     ///
 |     ///
 | ||||||
|     /// Returns `None` if the `TxOut` hasn't been scanned or if nothing matching was found there.
 |     /// Returns `None` if the `TxOut` hasn't been scanned or if nothing matching was found there.
 | ||||||
|     pub fn txout(&self, outpoint: OutPoint) -> Option<(&I, &TxOut)> { |     pub fn txout(&self, outpoint: OutPoint) -> Option<(&I, &TxOut)> { | ||||||
|         self.txouts |         self.txouts.get(&outpoint).map(|v| (&v.0, &v.1)) | ||||||
|             .get(&outpoint) |  | ||||||
|             .map(|(spk_i, txout)| (spk_i, txout)) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Returns the script that has been inserted at the `index`.
 |     /// Returns the script that has been inserted at the `index`.
 | ||||||
|  | |||||||
| @ -581,10 +581,7 @@ impl<A: Clone + Ord> TxGraph<A> { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (outpoint, txout) in changeset.txouts { |         for (outpoint, txout) in changeset.txouts { | ||||||
|             let tx_entry = self |             let tx_entry = self.txs.entry(outpoint.txid).or_default(); | ||||||
|                 .txs |  | ||||||
|                 .entry(outpoint.txid) |  | ||||||
|                 .or_insert_with(Default::default); |  | ||||||
| 
 | 
 | ||||||
|             match tx_entry { |             match tx_entry { | ||||||
|                 (TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */ |                 (TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */ | ||||||
| @ -597,13 +594,13 @@ impl<A: Clone + Ord> TxGraph<A> { | |||||||
| 
 | 
 | ||||||
|         for (anchor, txid) in changeset.anchors { |         for (anchor, txid) in changeset.anchors { | ||||||
|             if self.anchors.insert((anchor.clone(), txid)) { |             if self.anchors.insert((anchor.clone(), txid)) { | ||||||
|                 let (_, anchors, _) = self.txs.entry(txid).or_insert_with(Default::default); |                 let (_, anchors, _) = self.txs.entry(txid).or_default(); | ||||||
|                 anchors.insert(anchor); |                 anchors.insert(anchor); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for (txid, new_last_seen) in changeset.last_seen { |         for (txid, new_last_seen) in changeset.last_seen { | ||||||
|             let (_, _, last_seen) = self.txs.entry(txid).or_insert_with(Default::default); |             let (_, _, last_seen) = self.txs.entry(txid).or_default(); | ||||||
|             if new_last_seen > *last_seen { |             if new_last_seen > *last_seen { | ||||||
|                 *last_seen = new_last_seen; |                 *last_seen = new_last_seen; | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| mod tx_template; | mod tx_template; | ||||||
|  | #[allow(unused_imports)] | ||||||
| pub use tx_template::*; | pub use tx_template::*; | ||||||
| 
 | 
 | ||||||
| #[allow(unused_macros)] | #[allow(unused_macros)] | ||||||
|  | |||||||
| @ -27,9 +27,10 @@ fn insert_relevant_txs() { | |||||||
|     let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey(); |     let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey(); | ||||||
|     let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey(); |     let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey(); | ||||||
| 
 | 
 | ||||||
|     let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::default(); |     let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::new( | ||||||
|  |         KeychainTxOutIndex::new(10), | ||||||
|  |     ); | ||||||
|     graph.index.add_keychain((), descriptor); |     graph.index.add_keychain((), descriptor); | ||||||
|     graph.index.set_lookahead(&(), 10); |  | ||||||
| 
 | 
 | ||||||
|     let tx_a = Transaction { |     let tx_a = Transaction { | ||||||
|         output: vec![ |         output: vec![ | ||||||
| @ -118,12 +119,12 @@ fn test_list_owned_txouts() { | |||||||
|     let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)").unwrap(); |     let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)").unwrap(); | ||||||
|     let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)").unwrap(); |     let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)").unwrap(); | ||||||
| 
 | 
 | ||||||
|     let mut graph = |     let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>::new( | ||||||
|         IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>::default(); |         KeychainTxOutIndex::new(10), | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     graph.index.add_keychain("keychain_1".into(), desc_1); |     graph.index.add_keychain("keychain_1".into(), desc_1); | ||||||
|     graph.index.add_keychain("keychain_2".into(), desc_2); |     graph.index.add_keychain("keychain_2".into(), desc_2); | ||||||
|     graph.index.set_lookahead_for_all(10); |  | ||||||
| 
 | 
 | ||||||
|     // Get trusted and untrusted addresses
 |     // Get trusted and untrusted addresses
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,12 +18,14 @@ enum TestKeychain { | |||||||
|     Internal, |     Internal, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn init_txout_index() -> ( | fn init_txout_index( | ||||||
|  |     lookahead: u32, | ||||||
|  | ) -> ( | ||||||
|     bdk_chain::keychain::KeychainTxOutIndex<TestKeychain>, |     bdk_chain::keychain::KeychainTxOutIndex<TestKeychain>, | ||||||
|     Descriptor<DescriptorPublicKey>, |     Descriptor<DescriptorPublicKey>, | ||||||
|     Descriptor<DescriptorPublicKey>, |     Descriptor<DescriptorPublicKey>, | ||||||
| ) { | ) { | ||||||
|     let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::default(); |     let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::new(lookahead); | ||||||
| 
 | 
 | ||||||
|     let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only(); |     let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only(); | ||||||
|     let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap(); |     let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap(); | ||||||
| @ -46,7 +48,7 @@ fn spk_at_index(descriptor: &Descriptor<DescriptorPublicKey>, index: u32) -> Scr | |||||||
| 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; | ||||||
| 
 | 
 | ||||||
|     let (mut txout_index, _, _) = init_txout_index(); |     let (mut txout_index, _, _) = init_txout_index(0); | ||||||
|     let derive_to: BTreeMap<_, _> = |     let derive_to: BTreeMap<_, _> = | ||||||
|         [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into(); |         [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into(); | ||||||
|     assert_eq!( |     assert_eq!( | ||||||
| @ -64,19 +66,10 @@ fn test_set_all_derivation_indices() { | |||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_lookahead() { | fn test_lookahead() { | ||||||
|     let (mut txout_index, external_desc, internal_desc) = init_txout_index(); |     let (mut txout_index, external_desc, internal_desc) = init_txout_index(10); | ||||||
| 
 |  | ||||||
|     // ensure it does not break anything if lookahead is set multiple times
 |  | ||||||
|     (0..=10).for_each(|lookahead| txout_index.set_lookahead(&TestKeychain::External, lookahead)); |  | ||||||
|     (0..=20) |  | ||||||
|         .filter(|v| v % 2 == 0) |  | ||||||
|         .for_each(|lookahead| txout_index.set_lookahead(&TestKeychain::Internal, lookahead)); |  | ||||||
| 
 |  | ||||||
|     assert_eq!(txout_index.inner().all_spks().len(), 30); |  | ||||||
| 
 | 
 | ||||||
|     // given:
 |     // given:
 | ||||||
|     // - external lookahead set to 10
 |     // - external lookahead set to 10
 | ||||||
|     // - internal lookahead set to 20
 |  | ||||||
|     // when:
 |     // when:
 | ||||||
|     // - set external derivation index to value higher than last, but within the lookahead value
 |     // - set external derivation index to value higher than last, but within the lookahead value
 | ||||||
|     // expect:
 |     // expect:
 | ||||||
| @ -97,7 +90,7 @@ fn test_lookahead() { | |||||||
|         assert_eq!( |         assert_eq!( | ||||||
|             txout_index.inner().all_spks().len(), |             txout_index.inner().all_spks().len(), | ||||||
|             10 /* external lookahead */ + |             10 /* external lookahead */ + | ||||||
|             20 /* internal lookahead */ + |             10 /* internal lookahead */ + | ||||||
|             index as usize + 1 /* `derived` count */ |             index as usize + 1 /* `derived` count */ | ||||||
|         ); |         ); | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
| @ -127,7 +120,7 @@ fn test_lookahead() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // given:
 |     // given:
 | ||||||
|     // - internal lookahead is 20
 |     // - internal lookahead is 10
 | ||||||
|     // - internal derivation index is `None`
 |     // - internal derivation index is `None`
 | ||||||
|     // when:
 |     // when:
 | ||||||
|     // - derivation index is set ahead of current derivation index + lookahead
 |     // - derivation index is set ahead of current derivation index + lookahead
 | ||||||
| @ -148,7 +141,7 @@ fn test_lookahead() { | |||||||
|     assert_eq!( |     assert_eq!( | ||||||
|         txout_index.inner().all_spks().len(), |         txout_index.inner().all_spks().len(), | ||||||
|         10 /* external lookahead */ + |         10 /* external lookahead */ + | ||||||
|         20 /* internal lookahead */ + |         10 /* internal lookahead */ + | ||||||
|         20 /* external stored index count */ + |         20 /* external stored index count */ + | ||||||
|         25 /* internal stored index count */ |         25 /* internal stored index count */ | ||||||
|     ); |     ); | ||||||
| @ -226,8 +219,7 @@ fn test_lookahead() { | |||||||
| // - last used index should change as expected
 | // - last used index should change as expected
 | ||||||
| #[test] | #[test] | ||||||
| fn test_scan_with_lookahead() { | fn test_scan_with_lookahead() { | ||||||
|     let (mut txout_index, external_desc, _) = init_txout_index(); |     let (mut txout_index, external_desc, _) = init_txout_index(10); | ||||||
|     txout_index.set_lookahead_for_all(10); |  | ||||||
| 
 | 
 | ||||||
|     let spks: BTreeMap<u32, ScriptBuf> = [0, 10, 20, 30] |     let spks: BTreeMap<u32, ScriptBuf> = [0, 10, 20, 30] | ||||||
|         .into_iter() |         .into_iter() | ||||||
| @ -281,7 +273,7 @@ fn test_scan_with_lookahead() { | |||||||
| #[test] | #[test] | ||||||
| #[rustfmt::skip] | #[rustfmt::skip] | ||||||
| fn test_wildcard_derivations() { | fn test_wildcard_derivations() { | ||||||
|     let (mut txout_index, external_desc, _) = init_txout_index(); |     let (mut txout_index, external_desc, _) = init_txout_index(0); | ||||||
|     let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey(); |     let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey(); | ||||||
|     let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey(); |     let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey(); | ||||||
|     let external_spk_26 = external_desc.at_derivation_index(26).unwrap().script_pubkey(); |     let external_spk_26 = external_desc.at_derivation_index(26).unwrap().script_pubkey(); | ||||||
| @ -339,7 +331,7 @@ fn test_wildcard_derivations() { | |||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_non_wildcard_derivations() { | fn test_non_wildcard_derivations() { | ||||||
|     let mut txout_index = KeychainTxOutIndex::<TestKeychain>::default(); |     let mut txout_index = KeychainTxOutIndex::<TestKeychain>::new(0); | ||||||
| 
 | 
 | ||||||
|     let secp = bitcoin::secp256k1::Secp256k1::signing_only(); |     let secp = bitcoin::secp256k1::Secp256k1::signing_only(); | ||||||
|     let (no_wildcard_descriptor, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap(); |     let (no_wildcard_descriptor, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap(); | ||||||
|  | |||||||
| @ -477,7 +477,7 @@ fn populate_with_txids( | |||||||
| 
 | 
 | ||||||
|         let spk = tx |         let spk = tx | ||||||
|             .output |             .output | ||||||
|             .get(0) |             .first() | ||||||
|             .map(|txo| &txo.script_pubkey) |             .map(|txo| &txo.script_pubkey) | ||||||
|             .expect("tx must have an output"); |             .expect("tx must have an output"); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ use bdk_bitcoind_rpc::{ | |||||||
|     Emitter, |     Emitter, | ||||||
| }; | }; | ||||||
| use bdk_chain::{ | use bdk_chain::{ | ||||||
|     bitcoin::{Block, Transaction}, |     bitcoin::{constants::genesis_block, Block, Transaction}, | ||||||
|     indexed_tx_graph, keychain, |     indexed_tx_graph, keychain, | ||||||
|     local_chain::{self, CheckPoint, LocalChain}, |     local_chain::{self, CheckPoint, LocalChain}, | ||||||
|     ConfirmationTimeHeightAnchor, IndexedTxGraph, |     ConfirmationTimeHeightAnchor, IndexedTxGraph, | ||||||
| @ -64,9 +64,6 @@ struct RpcArgs { | |||||||
|     /// Starting block height to fallback to if no point of agreement if found
 |     /// Starting block height to fallback to if no point of agreement if found
 | ||||||
|     #[clap(env = "FALLBACK_HEIGHT", long, default_value = "0")] |     #[clap(env = "FALLBACK_HEIGHT", long, default_value = "0")] | ||||||
|     fallback_height: u32, |     fallback_height: u32, | ||||||
|     /// The unused-scripts lookahead will be kept at this size
 |  | ||||||
|     #[clap(long, default_value = "10")] |  | ||||||
|     lookahead: u32, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<RpcArgs> for Auth { | impl From<RpcArgs> for Auth { | ||||||
| @ -120,10 +117,11 @@ fn main() -> anyhow::Result<()> { | |||||||
|         "[{:>10}s] loaded initial changeset from db", |         "[{:>10}s] loaded initial changeset from db", | ||||||
|         start.elapsed().as_secs_f32() |         start.elapsed().as_secs_f32() | ||||||
|     ); |     ); | ||||||
|  |     let (init_chain_changeset, init_graph_changeset) = init_changeset; | ||||||
| 
 | 
 | ||||||
|     let graph = Mutex::new({ |     let graph = Mutex::new({ | ||||||
|         let mut graph = IndexedTxGraph::new(index); |         let mut graph = IndexedTxGraph::new(index); | ||||||
|         graph.apply_changeset(init_changeset.1); |         graph.apply_changeset(init_graph_changeset); | ||||||
|         graph |         graph | ||||||
|     }); |     }); | ||||||
|     println!( |     println!( | ||||||
| @ -131,7 +129,16 @@ fn main() -> anyhow::Result<()> { | |||||||
|         start.elapsed().as_secs_f32() |         start.elapsed().as_secs_f32() | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     let chain = Mutex::new(LocalChain::from_changeset(init_changeset.0)?); |     let chain = Mutex::new(if init_chain_changeset.is_empty() { | ||||||
|  |         let genesis_hash = genesis_block(args.network).block_hash(); | ||||||
|  |         let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash); | ||||||
|  |         let mut db = db.lock().unwrap(); | ||||||
|  |         db.stage((chain_changeset, Default::default())); | ||||||
|  |         db.commit()?; | ||||||
|  |         chain | ||||||
|  |     } else { | ||||||
|  |         LocalChain::from_changeset(init_chain_changeset)? | ||||||
|  |     }); | ||||||
|     println!( |     println!( | ||||||
|         "[{:>10}s] loaded local chain from changeset", |         "[{:>10}s] loaded local chain from changeset", | ||||||
|         start.elapsed().as_secs_f32() |         start.elapsed().as_secs_f32() | ||||||
| @ -161,13 +168,9 @@ fn main() -> anyhow::Result<()> { | |||||||
|     match rpc_cmd { |     match rpc_cmd { | ||||||
|         RpcCommands::Sync { rpc_args } => { |         RpcCommands::Sync { rpc_args } => { | ||||||
|             let RpcArgs { |             let RpcArgs { | ||||||
|                 fallback_height, |                 fallback_height, .. | ||||||
|                 lookahead, |  | ||||||
|                 .. |  | ||||||
|             } = rpc_args; |             } = rpc_args; | ||||||
| 
 | 
 | ||||||
|             graph.lock().unwrap().index.set_lookahead_for_all(lookahead); |  | ||||||
| 
 |  | ||||||
|             let chain_tip = chain.lock().unwrap().tip(); |             let chain_tip = chain.lock().unwrap().tip(); | ||||||
|             let rpc_client = rpc_args.new_client()?; |             let rpc_client = rpc_args.new_client()?; | ||||||
|             let mut emitter = Emitter::new(&rpc_client, chain_tip, fallback_height); |             let mut emitter = Emitter::new(&rpc_client, chain_tip, fallback_height); | ||||||
| @ -233,13 +236,10 @@ fn main() -> anyhow::Result<()> { | |||||||
|         } |         } | ||||||
|         RpcCommands::Live { rpc_args } => { |         RpcCommands::Live { rpc_args } => { | ||||||
|             let RpcArgs { |             let RpcArgs { | ||||||
|                 fallback_height, |                 fallback_height, .. | ||||||
|                 lookahead, |  | ||||||
|                 .. |  | ||||||
|             } = rpc_args; |             } = rpc_args; | ||||||
|             let sigterm_flag = start_ctrlc_handler(); |             let sigterm_flag = start_ctrlc_handler(); | ||||||
| 
 | 
 | ||||||
|             graph.lock().unwrap().index.set_lookahead_for_all(lookahead); |  | ||||||
|             let last_cp = chain.lock().unwrap().tip(); |             let last_cp = chain.lock().unwrap().tip(); | ||||||
| 
 | 
 | ||||||
|             println!( |             println!( | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user