Skip to content

Commit 2181c4b

Browse files
ValuedMammalMusab1258LagginTimesevanlinjin
committed
feat(rpc)!: FilterIter API redesign
The API now consists of the methods `new` and `next`. The local checkpoint and SPK inventory are provided to the constructor. `next` is now responsible for locating the point of agreement. The next filter to fetch is determined by the `next_block_hash` field of `GetBlockHeaderResult`. If the next header has negative confirmations due to a reorg, we rewind the internal state until we find a header still in the best chain. `Event` is changed to a simple struct containing `cp` and optional `block`. The checkpoint is updated on each iteration whether or not it corresponds to a matching block. We use `CheckPoint::insert` which will also purge evicted blocks if needed. Change implementation of `find_base` to use `get_block_header_info` which helps to reduce the number of RPC calls. Removed `EventInner`. Add test `event_checkpoint_connects_to_local_chain` to check the expected events after a reorg, and check that intermediate updates can be applied to the local chain. Co-authored-by: Musab1258 <[email protected]> Co-authored-by: Wei Chen <[email protected]> Co-authored-by: 志宇 <[email protected]>
1 parent 993ae06 commit 2181c4b

File tree

3 files changed

+261
-356
lines changed

3 files changed

+261
-356
lines changed
Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
#![allow(clippy::print_stdout)]
1+
#![allow(clippy::print_stdout, clippy::print_stderr)]
22
use std::time::Instant;
33

44
use anyhow::Context;
5-
use bdk_bitcoind_rpc::bip158::{Event, EventInner, FilterIter};
5+
use bdk_bitcoind_rpc::bip158::{Event, FilterIter};
66
use bdk_chain::bitcoin::{constants::genesis_block, secp256k1::Secp256k1, Network};
77
use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
88
use bdk_chain::local_chain::LocalChain;
99
use bdk_chain::miniscript::Descriptor;
1010
use bdk_chain::{BlockId, ConfirmationBlockTime, IndexedTxGraph, SpkIterator};
1111
use bdk_testenv::anyhow;
12-
use bitcoin::Address;
1312

1413
// This example shows how BDK chain and tx-graph structures are updated using compact
1514
// filters syncing. Assumes a connection can be made to a bitcoin node via environment
1615
// variables `RPC_URL` and `RPC_COOKIE`.
1716

1817
// Usage: `cargo run -p bdk_bitcoind_rpc --example filter_iter`
1918

20-
const EXTERNAL: &str = "tr([7d94197e]tprv8ZgxMBicQKsPe1chHGzaa84k1inY2nAXUL8iPSyWESPrEst4E5oCFXhPATqj5fvw34LDknJz7rtXyEC4fKoXryUdc9q87pTTzfQyv61cKdE/86'/1'/0'/0/*)#uswl2jj7";
21-
const INTERNAL: &str = "tr([7d94197e]tprv8ZgxMBicQKsPe1chHGzaa84k1inY2nAXUL8iPSyWESPrEst4E5oCFXhPATqj5fvw34LDknJz7rtXyEC4fKoXryUdc9q87pTTzfQyv61cKdE/86'/1'/0'/1/*)#dyt7h8zx";
19+
const EXTERNAL: &str = "tr([83737d5e/86'/1'/0']tpubDDR5GgtoxS8fJyjjvdahN4VzV5DV6jtbcyvVXhEKq2XtpxjxBXmxH3r8QrNbQqHg4bJM1EGkxi7Pjfkgnui9jQWqS7kxHvX6rhUeriLDKxz/0/*)";
20+
const INTERNAL: &str = "tr([83737d5e/86'/1'/0']tpubDDR5GgtoxS8fJyjjvdahN4VzV5DV6jtbcyvVXhEKq2XtpxjxBXmxH3r8QrNbQqHg4bJM1EGkxi7Pjfkgnui9jQWqS7kxHvX6rhUeriLDKxz/1/*)";
2221
const SPK_COUNT: u32 = 25;
2322
const NETWORK: Network = Network::Signet;
2423

25-
const START_HEIGHT: u32 = 170_000;
26-
const START_HASH: &str = "00000041c812a89f084f633e4cf47e819a2f6b1c0a15162355a930410522c99d";
24+
const START_HEIGHT: u32 = 205_000;
25+
const START_HASH: &str = "0000002bd0f82f8c0c0f1e19128f84c938763641dba85c44bdb6aed1678d16cb";
2726

2827
fn main() -> anyhow::Result<()> {
2928
// Setup receiving chain and graph structures.
@@ -52,37 +51,22 @@ fn main() -> anyhow::Result<()> {
5251
let rpc_client =
5352
bitcoincore_rpc::Client::new(&url, bitcoincore_rpc::Auth::CookieFile(cookie.into()))?;
5453

55-
// Initialize block emitter
56-
let cp = chain.tip();
57-
let start_height = cp.height();
58-
let mut emitter = FilterIter::new_with_checkpoint(&rpc_client, cp);
54+
// Initialize `FilterIter`
55+
let mut spks = vec![];
5956
for (_, desc) in graph.index.keychains() {
60-
let spks = SpkIterator::new_with_range(desc, 0..SPK_COUNT).map(|(_, spk)| spk);
61-
emitter.add_spks(spks);
57+
spks.extend(SpkIterator::new_with_range(desc, 0..SPK_COUNT).map(|(_, s)| s));
6258
}
59+
let iter = FilterIter::new(&rpc_client, chain.tip(), spks);
6360

6461
let start = Instant::now();
6562

66-
// Sync
67-
if let Some(tip) = emitter.get_tip()? {
68-
let blocks_to_scan = tip.height - start_height;
69-
70-
for event in emitter.by_ref() {
71-
let event = event?;
72-
let curr = event.height();
73-
// apply relevant blocks
74-
if let Event::Block(EventInner { height, ref block }) = event {
75-
let _ = graph.apply_block_relevant(block, height);
76-
println!("Matched block {curr}");
77-
}
78-
if curr % 1000 == 0 {
79-
let progress = (curr - start_height) as f32 / blocks_to_scan as f32;
80-
println!("[{:.2}%]", progress * 100.0);
81-
}
82-
}
83-
// update chain
84-
if let Some(cp) = emitter.chain_update() {
85-
let _ = chain.apply_update(cp)?;
63+
for res in iter {
64+
let Event { cp, block } = res?;
65+
let height = cp.height();
66+
let _ = chain.apply_update(cp)?;
67+
if let Some(block) = block {
68+
let _ = graph.apply_block_relevant(&block, height);
69+
println!("Matched block {height}");
8670
}
8771
}
8872

@@ -105,9 +89,18 @@ fn main() -> anyhow::Result<()> {
10589
}
10690
}
10791

108-
let unused_spk = graph.index.reveal_next_spk("external").unwrap().0 .1;
109-
let unused_address = Address::from_script(&unused_spk, NETWORK)?;
110-
println!("Next external address: {unused_address}");
92+
for canon_tx in graph.graph().list_canonical_txs(
93+
&chain,
94+
chain.tip().block_id(),
95+
bdk_chain::CanonicalizationParams::default(),
96+
) {
97+
if !canon_tx.chain_position.is_confirmed() {
98+
eprintln!(
99+
"ERROR: canonical tx should be confirmed {}",
100+
canon_tx.tx_node.txid
101+
);
102+
}
103+
}
111104

112105
Ok(())
113106
}

0 commit comments

Comments
 (0)