-
Notifications
You must be signed in to change notification settings - Fork 320
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7969898
commit 1074412
Showing
5 changed files
with
533 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
#![allow(clippy::print_stdout)] | ||
use std::time::Instant; | ||
|
||
use anyhow::Context; | ||
use bdk_bitcoind_rpc::bip158::{Event, EventInner, FilterIter}; | ||
use bdk_chain::bitcoin::{constants::genesis_block, secp256k1::Secp256k1, Network}; | ||
use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex; | ||
use bdk_chain::local_chain::LocalChain; | ||
use bdk_chain::miniscript::Descriptor; | ||
use bdk_chain::{BlockId, ConfirmationBlockTime, IndexedTxGraph, SpkIterator}; | ||
use bdk_testenv::anyhow; | ||
|
||
// This example shows how BDK chain and tx-graph structures are updated using compact | ||
// filters syncing. Assumes a connection can be made to a bitcoin node via environment | ||
// variables `RPC_URL` and `RPC_COOKIE`. | ||
|
||
// Usage: `cargo run -p bdk_bitcoind_rpc --example bip158` | ||
|
||
const EXTERNAL: &str = "tr([7d94197e]tprv8ZgxMBicQKsPe1chHGzaa84k1inY2nAXUL8iPSyWESPrEst4E5oCFXhPATqj5fvw34LDknJz7rtXyEC4fKoXryUdc9q87pTTzfQyv61cKdE/86'/1'/0'/0/*)#uswl2jj7"; | ||
const INTERNAL: &str = "tr([7d94197e]tprv8ZgxMBicQKsPe1chHGzaa84k1inY2nAXUL8iPSyWESPrEst4E5oCFXhPATqj5fvw34LDknJz7rtXyEC4fKoXryUdc9q87pTTzfQyv61cKdE/86'/1'/0'/1/*)#dyt7h8zx"; | ||
const SPK_COUNT: u32 = 25; | ||
const NETWORK: Network = Network::Signet; | ||
|
||
const START_HEIGHT: u32 = 170_000; | ||
const START_HASH: &str = "00000041c812a89f084f633e4cf47e819a2f6b1c0a15162355a930410522c99d"; | ||
|
||
fn main() -> anyhow::Result<()> { | ||
// Setup receiving chain and graph structures. | ||
let secp = Secp256k1::new(); | ||
let (descriptor, _) = Descriptor::parse_descriptor(&secp, EXTERNAL)?; | ||
let (change_descriptor, _) = Descriptor::parse_descriptor(&secp, INTERNAL)?; | ||
let (mut chain, _) = LocalChain::from_genesis_hash(genesis_block(NETWORK).block_hash()); | ||
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, KeychainTxOutIndex<&str>>::new({ | ||
let mut index = KeychainTxOutIndex::default(); | ||
index.insert_descriptor("external", descriptor.clone())?; | ||
index.insert_descriptor("internal", change_descriptor.clone())?; | ||
index | ||
}); | ||
|
||
// Assume a minimum birthday height | ||
let block = BlockId { | ||
height: START_HEIGHT, | ||
hash: START_HASH.parse()?, | ||
}; | ||
let _ = chain.insert_block(block)?; | ||
|
||
// Configure RPC client | ||
let url = std::env::var("RPC_URL").context("must set RPC_URL")?; | ||
let cookie = std::env::var("RPC_COOKIE").context("must set RPC_COOKIE")?; | ||
let rpc_client = | ||
bitcoincore_rpc::Client::new(&url, bitcoincore_rpc::Auth::CookieFile(cookie.into()))?; | ||
|
||
// Initialize block emitter | ||
let cp = chain.tip(); | ||
let start_height = cp.height(); | ||
let mut emitter = FilterIter::new_with_checkpoint(&rpc_client, cp); | ||
for (_, desc) in graph.index.keychains() { | ||
let spks = SpkIterator::new_with_range(desc, 0..SPK_COUNT).map(|(_, spk)| spk); | ||
emitter.add_spks(spks); | ||
} | ||
|
||
let start = Instant::now(); | ||
|
||
// Sync | ||
if let Some(tip) = emitter.get_tip()? { | ||
let blocks_to_scan = tip.height - start_height; | ||
|
||
for event in emitter.by_ref() { | ||
let event = event?; | ||
let curr = event.height(); | ||
// apply relevant blocks | ||
if let Event::Block(EventInner { height, ref block }) = event { | ||
let _ = graph.apply_block_relevant(block, height); | ||
println!("Matched block {}", curr); | ||
} | ||
if curr % 1000 == 0 { | ||
let progress = (curr - start_height) as f32 / blocks_to_scan as f32; | ||
println!("[{:.2}%]", progress * 100.0); | ||
} | ||
} | ||
// update chain | ||
if let Some(tip) = emitter.chain_update() { | ||
let _ = chain.apply_update(tip)?; | ||
} | ||
} | ||
|
||
println!("\ntook: {}s", start.elapsed().as_secs()); | ||
println!("Local tip: {}", chain.tip().height()); | ||
let unspent: Vec<_> = graph | ||
.graph() | ||
.filter_chain_unspents( | ||
&chain, | ||
chain.tip().block_id(), | ||
graph.index.outpoints().clone(), | ||
) | ||
.collect(); | ||
if !unspent.is_empty() { | ||
println!("\nUnspent"); | ||
for (index, utxo) in unspent { | ||
// (k, index) | value | outpoint | | ||
println!("{:?} | {} | {}", index, utxo.txout.value, utxo.outpoint,); | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.