-
Notifications
You must be signed in to change notification settings - Fork 422
Introduce evicted-at/last-evicted timestamps
#1811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b1461f2
ec25b10
4a0b920
40ceef1
5b7f851
b3d17ad
241dd7d
bfaf589
5e2f242
4b979c6
3be6c2b
5f6dfe7
ef45337
f2a2095
dc452a1
66fa256
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,8 +10,9 @@ | |
| #![warn(missing_docs)] | ||
|
|
||
| use bdk_core::{BlockId, CheckPoint}; | ||
| use bitcoin::{block::Header, Block, BlockHash, Transaction}; | ||
| use bitcoin::{block::Header, Block, BlockHash, Transaction, Txid}; | ||
| use bitcoincore_rpc::bitcoincore_rpc_json; | ||
| use std::collections::HashSet; | ||
|
|
||
| pub mod bip158; | ||
|
|
||
|
|
@@ -64,17 +65,19 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> { | |
| } | ||
| } | ||
|
|
||
| /// Emit mempool transactions, alongside their first-seen unix timestamps. | ||
| /// Emit mempool transactions and capture the initial snapshot of all mempool [`Txid`]s. | ||
| /// | ||
| /// This method emits each transaction only once, unless we cannot guarantee the transaction's | ||
| /// ancestors are already emitted. | ||
| /// This method returns a [`MempoolEvent`] containing the full transactions (with their | ||
| /// first-seen unix timestamps) that were emitted, and the set of all [`Txid`]s present from the | ||
| /// initial mempool query. Each transaction is emitted only once, unless we cannot guarantee the | ||
| /// transaction's ancestors are already emitted. | ||
| /// | ||
| /// To understand why, consider a receiver which filters transactions based on whether it | ||
| /// alters the UTXO set of tracked script pubkeys. If an emitted mempool transaction spends a | ||
| /// tracked UTXO which is confirmed at height `h`, but the receiver has only seen up to block | ||
| /// of height `h-1`, we want to re-emit this transaction until the receiver has seen the block | ||
| /// at height `h`. | ||
| pub fn mempool(&mut self) -> Result<Vec<(Transaction, u64)>, bitcoincore_rpc::Error> { | ||
| pub fn mempool(&mut self) -> Result<MempoolEvent, bitcoincore_rpc::Error> { | ||
| let client = self.client; | ||
|
|
||
| // This is the emitted tip height during the last mempool emission. | ||
|
|
@@ -91,8 +94,11 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> { | |
| let prev_mempool_time = self.last_mempool_time; | ||
| let mut latest_time = prev_mempool_time; | ||
|
|
||
| let txs_to_emit = client | ||
| .get_raw_mempool_verbose()? | ||
| // Get the raw mempool result from the RPC client. | ||
| let raw_mempool = client.get_raw_mempool_verbose()?; | ||
| let raw_mempool_txids = raw_mempool.keys().copied().collect::<HashSet<_>>(); | ||
|
|
||
| let emitted_txs = raw_mempool | ||
| .into_iter() | ||
| .filter_map({ | ||
| let latest_time = &mut latest_time; | ||
|
|
@@ -128,7 +134,11 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> { | |
| self.last_mempool_time = latest_time; | ||
| self.last_mempool_tip = Some(self.last_cp.height()); | ||
|
|
||
| Ok(txs_to_emit) | ||
| Ok(MempoolEvent { | ||
| emitted_txs, | ||
| raw_mempool_txids, | ||
| last_seen: latest_time as u64, | ||
| }) | ||
| } | ||
|
|
||
| /// Emit the next block height and header (if any). | ||
|
|
@@ -144,6 +154,37 @@ impl<'c, C: bitcoincore_rpc::RpcApi> Emitter<'c, C> { | |
| } | ||
| } | ||
|
|
||
| /// A new emission from mempool. | ||
| #[derive(Debug)] | ||
| pub struct MempoolEvent { | ||
| /// Emitted mempool transactions with their first‐seen unix timestamps. | ||
| pub emitted_txs: Vec<(Transaction, u64)>, | ||
|
|
||
| /// Set of all [`Txid`]s from the raw mempool result, including transactions that may have been | ||
| /// confirmed or evicted during processing. This is used to determine which expected | ||
| /// transactions are missing. | ||
| pub raw_mempool_txids: HashSet<Txid>, | ||
LagginTimes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// The latest first-seen epoch of emitted mempool transactions. | ||
| pub last_seen: u64, | ||
LagginTimes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| impl MempoolEvent { | ||
| /// Given an iterator of expected [`Txid`]s, return those that are missing from the mempool. | ||
| pub fn evicted_txids( | ||
| &self, | ||
| expected_unconfirmed_txids: impl IntoIterator<Item = Txid>, | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For spk-based syncing we want to use all canonical txids (including confirmed) to determine evicted txs. The reason is because spk-based APIs returns both confirmed and unconfirmed under a given spk and that a missing previously-confirmed tx is also evicted from the mempool. For rpc-based, we obviously want to only input unconfirmed txs as block (confirmed events) are handled separately... We can add an Another idea is to compare the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it's best to combine those two ideas. This way we don't have to get something from our receiving structures (
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that the entire txid history is strictly needed in the expected set.
Perhaps, but maybe we're only concerned with reorgs below some number of confirmations? For a busy wallet the set of expected txids could be quite large which could hinder sync performance over time, considering that the normal fate of a transaction is to gain confirmations and never disappear from the blockchain.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Or have a method that takes an iterator of canonical txs, that way the caller can filter them on a number of confirmations for example. |
||
| ) -> HashSet<Txid> { | ||
| let expected_set = expected_unconfirmed_txids | ||
| .into_iter() | ||
| .collect::<HashSet<_>>(); | ||
| expected_set | ||
| .difference(&self.raw_mempool_txids) | ||
| .copied() | ||
| .collect() | ||
| } | ||
| } | ||
|
|
||
| /// A newly emitted block from [`Emitter`]. | ||
| #[derive(Debug)] | ||
| pub struct BlockEvent<B> { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.