-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathbuilder.rs
More file actions
157 lines (147 loc) · 5.08 KB
/
builder.rs
File metadata and controls
157 lines (147 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Construct a [`LightClient`] by using a reference to a [`Wallet`].
//!
//! ## Details
//!
//! The node has a number of configurations. Notably, the height of in the blockchain to start a
//! wallet recovery and the nodes on the peer-to-peer network are both configurable.
//!
//! ```no_run
//! # const RECEIVE: &str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/0/*)";
//! # const CHANGE: &str = "tr([7d94197e/86'/1'/0']tpubDCyQVJj8KzjiQsFjmb3KwECVXPvMwvAxxZGCP9XmWSopmjW3bCV3wD7TgxrUhiGSueDS1MU5X1Vb1YjYcp8jitXc5fXfdC1z68hDDEyKRNr/1/*)";
//! use std::net::{IpAddr, Ipv4Addr};
//! use std::path::PathBuf;
//! use std::time::Duration;
//! use bdk_wallet::Wallet;
//! use bdk_kyoto::bip157::{Network, TrustedPeer};
//! use bdk_kyoto::builder::{Builder, BuilderExt};
//! use bdk_kyoto::{LightClient, ScanType};
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! // Add specific peers to connect to.
//! let peer = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
//! let trusted = TrustedPeer::from_ip(peer);
//!
//! let db_path = ".".parse::<PathBuf>()?;
//!
//! let mut wallet = Wallet::create(RECEIVE, CHANGE)
//! .network(Network::Signet)
//! .create_wallet_no_persist()?;
//!
//! let scan_type = ScanType::Sync;
//!
//! let LightClient {
//! requester,
//! info_subscriber,
//! warning_subscriber,
//! update_subscriber,
//! node
//! } = Builder::new(Network::Signet)
//! // A node may handle multiple connections
//! .required_peers(2)
//! // Choose where to store node data
//! .data_dir(db_path)
//! // How long peers have to respond messages
//! .response_timeout(Duration::from_secs(2))
//! // Added trusted peers to initialize the sync
//! .add_peer(trusted)
//! .build_with_wallet(&wallet, scan_type)?;
//! Ok(())
//! }
//! ```
use std::fmt::Display;
use bdk_wallet::bitcoin::Network;
use bdk_wallet::chain::keychain_txout::KeychainTxOutIndex;
use bdk_wallet::{
chain::{CheckPoint, IndexedTxGraph},
KeychainKind,
};
pub use bip157::Builder;
use bip157::{chain::ChainState, HeaderCheckpoint};
use crate::{LightClient, ScanType, UpdateSubscriber};
const IMPOSSIBLE_REORG_DEPTH: usize = 7;
/// Build a compact block filter client and node for a specified wallet
pub trait BuilderExt {
/// Attempt to build the node with scripts from a [`Wallet`] and following a [`ScanType`].
fn build_with_wallet(
self,
txout_index: KeychainTxOutIndex<KeychainKind>,
chain_tip: CheckPoint,
network: Network,
scan_type: ScanType,
) -> Result<LightClient, BuilderError>;
}
impl BuilderExt for Builder {
fn build_with_wallet(
mut self,
txout_index: KeychainTxOutIndex<KeychainKind>,
chain_tip: CheckPoint,
network: Network,
scan_type: ScanType,
) -> Result<LightClient, BuilderError> {
if self.network().ne(&network) {
return Err(BuilderError::NetworkMismatch);
}
match scan_type {
ScanType::Sync => {
let current_cp = chain_tip.clone();
let sync_start = walk_back_max_reorg(current_cp);
self = self.chain_state(ChainState::Checkpoint(sync_start));
}
ScanType::Recovery {
used_script_index: _,
checkpoint,
} => self = self.chain_state(ChainState::Checkpoint(checkpoint)),
}
let (node, client) = self.build();
let bip157::Client {
requester,
info_rx,
warn_rx,
event_rx,
} = client;
let indexed_graph = IndexedTxGraph::new(txout_index);
let update_subscriber = UpdateSubscriber::new(
requester.clone(),
scan_type,
event_rx,
chain_tip,
indexed_graph,
);
Ok(LightClient {
requester,
info_subscriber: info_rx,
warning_subscriber: warn_rx,
update_subscriber,
node,
})
}
}
/// Walk back 7 blocks in case the last sync was an orphan block.
fn walk_back_max_reorg(checkpoint: CheckPoint) -> HeaderCheckpoint {
let mut ret_cp = HeaderCheckpoint::new(checkpoint.height(), checkpoint.hash());
let cp_iter = checkpoint.iter();
for (index, next) in cp_iter.enumerate() {
if index > IMPOSSIBLE_REORG_DEPTH {
return ret_cp;
}
ret_cp = HeaderCheckpoint::new(next.height(), next.hash());
}
ret_cp
}
/// Errors the builder may throw.
#[derive(Debug)]
pub enum BuilderError {
/// The wallet network and node network do not match.
NetworkMismatch,
}
impl Display for BuilderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuilderError::NetworkMismatch => {
write!(f, "wallet network and node network do not match")
}
}
}
}
impl std::error::Error for BuilderError {}