Add populate_anchor_cache method to bdk#2005
Conversation
|
Thank you for approaching this. The ticket was very brief and was not specific enough - sorry about that. Let me clarify what we are looking for.
In other words, |
c26661f to
9b22afe
Compare
|
Thanks for the contribution! A couple of things to take care of:
|
9b22afe to
dacdcd0
Compare
| Box::new(self.full_txs().flat_map(move |tx_node| { | ||
| tx_node.anchors.iter().map(move |anchor| { | ||
| let block_id = anchor.block_id; | ||
| ((tx_node.txid, block_id.hash), *anchor) |
There was a problem hiding this comment.
You are getting the block hash from the anchor, so the API doesn't need to take in the block hash separately.
| } | ||
|
|
||
| /// Extension trait to expose anchors in a public-friendly way | ||
| trait TxGraphExt { |
There was a problem hiding this comment.
Only introduce extension traits out of necessity. Is there another method on TxGraph that you can use? If not, you can introduce a method on TxGraph directly.
dacdcd0 to
030a4e0
Compare
| /// Iterate over all tx outputs known by [`TxGraph`]. | ||
| /// | ||
| /// This returns an iterator over all anchors in the graph as (txid, anchor) pairs | ||
| pub fn anchors(&self) -> impl Iterator<Item = (Txid, &A)> + '_ { | ||
| self.anchors | ||
| .iter() | ||
| .flat_map(|(txid, anchors)| anchors.iter().map(move |a| (*txid, a))) | ||
| } | ||
|
|
||
| /// This includes txouts of both full transactions as well as floating transactions. |
There was a problem hiding this comment.
I think you inserted anchors in the middle of the doc comments of all_txouts.
|
|
||
| // This avoids re-fetching known anchor confirmations from Electrum. | ||
| // Hold the lock for the entire anchor extraction | ||
| let graph_guard = graph.lock().unwrap(); |
There was a problem hiding this comment.
Have you tried running this? Since we lock graph again on line 143, wouldn't this result in a deadlock?
| // This avoids re-fetching known anchor confirmations from Electrum. | ||
| // Hold the lock for the entire anchor extraction | ||
| let graph_guard = graph.lock().unwrap(); | ||
| // Collect anchors to release the lock quickly | ||
| let mut anchors = Vec::new(); | ||
| for (txid, anchor) in graph_guard.graph().anchors() { | ||
| anchors.push((txid, *anchor)); // Dereference instead of clone for Copy types | ||
| } | ||
| client.populate_anchor_cache(anchors); | ||
|
|
There was a problem hiding this comment.
Some of these comments are explaining very obvious things in a way that doesn’t add much beyond reading the code itself.
There was a problem hiding this comment.
Also, how about we populate the anchor & tx cache under a single lock of graph?
crates/chain/src/tx_graph.rs
Outdated
| /// This returns an iterator over all anchors in the graph as (txid, anchor) pairs | ||
| pub fn anchors(&self) -> impl Iterator<Item = (Txid, &A)> + '_ { | ||
| self.anchors | ||
| .iter() | ||
| .flat_map(|(txid, anchors)| anchors.iter().map(move |a| (*txid, a))) | ||
| } |
There was a problem hiding this comment.
Instead of introducing this anchors method, how about we make use of the all_anchors method we have already?
I propose changing BdkElectrumClient::populate_anchor_cache to the following:
/// Insert anchors into the anchor cache so that they don’t have to be fetched again from
/// Electrum. Typically used to pre-populate the cache from an existing `TxGraph`.
pub fn populate_anchor_cache(
&self,
tx_anchors: impl IntoIterator<Item = (Txid, impl IntoIterator<Item = ConfirmationBlockTime>)>,
) {
let mut cache = self.anchor_cache.lock().unwrap();
for (txid, anchors) in tx_anchors {
for anchor in anchors {
cache.insert((txid, anchor.block_id.hash), anchor);
}
}
}Using the API will look like this:
let graph = graph.lock().unwrap();
client.populate_anchor_cache(graph.graph().all_anchors().clone());|
@Her-Code Thanks for taking this on! It would be really helpful to have this in soon. Do you think you’d be able to complete it by the end of the week, or would you need more time? |
030a4e0 to
1511cf4
Compare
|
I've implemented the anchor caching using all_anchors() as you suggested. I noticed the original implementation could potentially create nested locks: let graph = graph.lock().unwrap();
client.populate_anchor_cache(graph.graph().all_anchors().clone());so I added explicit scoping with curly braces to ensure proper lock management: {
// Lock graph mutex - released automatically at scope end
// Cache all anchors while holding the lock
let graph = graph.lock().unwrap();
client.populate_anchor_cache(graph.graph().all_anchors().clone());
} |
Also updates the `example_electrum` example and `populate_tx_cache` documentation to be consistent with `populate_anchor_cache`.
1511cf4 to
191bdb1
Compare
This PR addresses #1982
It introduces functionality to populate the anchor cache, improving how BDK handles stateful or performance-critical anchor data.
Changes
populate_anchor_cachemethod toBdkElectrumClientinbdk-coreFollow-up work will extend this functionality to
bdk-wallet.