Skip to content

Commit d6c075d

Browse files
committed
deps!: update to bdk at b707586
- `apply_update` no longer requires std - Removed `apply_update_at` - `start_sync_with_revealed_spks` is now behind "std" feature - Added `start_sync_at` - `start_sync_*` includes the expected spk history - Add example test for mempool eviction, includes persistence - Update bdk_file_store, which uses the latest from bdk_core - `start_full_scan` requires std feature Note that `tx_graph::ChangeSet` gained a new default-able field `last_evicted` to account for evictions.
1 parent 3e61d2a commit d6c075d

File tree

14 files changed

+269
-122
lines changed

14 files changed

+269
-122
lines changed

examples/example_wallet_electrum/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
8-
bdk_electrum = { version = "0.21" }
8+
#bdk_electrum = { version = "0.21" }
9+
bdk_electrum = { git = "https://github.com/bitcoindevkit/bdk", rev = "b70758652d1c819c88d92765905d09e26b951ee2" }
910
anyhow = "1"

examples/example_wallet_electrum/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const ELECTRUM_URL: &str = "ssl://electrum.blockstream.info:60002";
2222
fn main() -> Result<(), anyhow::Error> {
2323
let db_path = "bdk-electrum-example.db";
2424

25-
let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), db_path)?;
25+
let (mut db, _) = Store::<bdk_wallet::ChangeSet>::load_or_create(DB_MAGIC.as_bytes(), db_path)?;
2626

2727
let wallet_opt = Wallet::load()
2828
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))

examples/example_wallet_esplora_async/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ edition = "2021"
77

88
[dependencies]
99
bdk_wallet = { path = "../../wallet", features = ["rusqlite"] }
10-
bdk_esplora = { version = "0.20", features = ["async-https", "tokio"] }
10+
#bdk_esplora = { version = "0.20", features = ["async-https", "tokio"] }
11+
bdk_esplora = { git = "https://github.com/bitcoindevkit/bdk", rev = "b70758652d1c819c88d92765905d09e26b951ee2", features = ["async-https", "tokio"] }
12+
bdk_testenv = { git = "https://github.com/bitcoindevkit/bdk", rev = "b70758652d1c819c88d92765905d09e26b951ee2" }
1113
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
1214
anyhow = "1"
Lines changed: 170 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
#![allow(unused)]
12
use std::{collections::BTreeSet, io::Write};
23

34
use anyhow::Ok;
45
use bdk_esplora::{esplora_client, EsploraAsyncExt};
6+
use bdk_testenv::bitcoincore_rpc::RpcApi;
57
use bdk_wallet::{
68
bitcoin::{Amount, Network},
79
rusqlite::Connection,
@@ -13,14 +15,16 @@ const STOP_GAP: usize = 5;
1315
const PARALLEL_REQUESTS: usize = 5;
1416

1517
const DB_PATH: &str = "bdk-example-esplora-async.sqlite";
16-
const NETWORK: Network = Network::Signet;
18+
// const NETWORK: Network = Network::Signet;
19+
const NETWORK: Network = Network::Regtest;
1720
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
1821
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
1922
const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
2023

2124
#[tokio::main]
2225
async fn main() -> Result<(), anyhow::Error> {
23-
let mut conn = Connection::open(DB_PATH)?;
26+
// let mut conn = Connection::open(DB_PATH)?;
27+
let mut conn = Connection::open_in_memory()?;
2428

2529
let wallet_opt = Wallet::load()
2630
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
@@ -35,57 +39,176 @@ async fn main() -> Result<(), anyhow::Error> {
3539
.create_wallet(&mut conn)?,
3640
};
3741

38-
let address = wallet.next_unused_address(KeychainKind::External);
42+
// let address = wallet.next_unused_address(KeychainKind::External);
43+
let recv_addr = wallet.next_unused_address(KeychainKind::External);
3944
wallet.persist(&mut conn)?;
40-
println!("Next unused address: ({}) {}", address.index, address);
41-
42-
let balance = wallet.balance();
43-
println!("Wallet balance before syncing: {}", balance.total());
44-
45-
print!("Syncing...");
46-
let client = esplora_client::Builder::new(ESPLORA_URL).build_async()?;
47-
48-
let request = wallet.start_full_scan().inspect({
49-
let mut stdout = std::io::stdout();
50-
let mut once = BTreeSet::<KeychainKind>::new();
51-
move |keychain, spk_i, _| {
52-
if once.insert(keychain) {
53-
print!("\nScanning keychain [{:?}]", keychain);
54-
}
55-
print!(" {:<3}", spk_i);
56-
stdout.flush().expect("must flush")
57-
}
58-
});
59-
60-
let update = client
61-
.full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
62-
.await?;
63-
64-
wallet.apply_update(update)?;
65-
wallet.persist(&mut conn)?;
66-
println!();
45+
// println!("Next unused address: ({}) {}", address.index, address);
46+
47+
// let balance = wallet.balance();
48+
// println!("Wallet balance before syncing: {}", balance.total());
49+
50+
// print!("Syncing...");
51+
// let client = esplora_client::Builder::new(ESPLORA_URL).build_async()?;
52+
53+
// let request = wallet.start_full_scan().inspect({
54+
// let mut stdout = std::io::stdout();
55+
// let mut once = BTreeSet::<KeychainKind>::new();
56+
// move |keychain, spk_i, _| {
57+
// if once.insert(keychain) {
58+
// print!("\nScanning keychain [{:?}]", keychain);
59+
// }
60+
// print!(" {:<3}", spk_i);
61+
// stdout.flush().expect("must flush")
62+
// }
63+
// });
64+
65+
// let update = client
66+
// .full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
67+
// .await?;
68+
69+
// wallet.apply_update(update)?;
70+
// wallet.persist(&mut conn)?;
71+
// println!();
72+
73+
// let balance = wallet.balance();
74+
// println!("Wallet balance after syncing: {}", balance.total());
75+
76+
// if balance.total() < SEND_AMOUNT {
77+
// println!(
78+
// "Please send at least {} to the receiving address",
79+
// SEND_AMOUNT
80+
// );
81+
// std::process::exit(0);
82+
// }
83+
84+
// let mut tx_builder = wallet.build_tx();
85+
// tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);
86+
87+
// let mut psbt = tx_builder.finish()?;
88+
// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
89+
// assert!(finalized);
90+
91+
// let tx = psbt.extract_tx()?;
92+
// client.broadcast(&tx).await?;
93+
// println!("Tx broadcasted! Txid: {}", tx.compute_txid());
94+
95+
use bdk_testenv::bitcoincore_rpc::bitcoincore_rpc_json::CreateRawTransactionInput;
96+
use bdk_testenv::TestEnv;
97+
let env = TestEnv::new()?;
98+
99+
// premine
100+
let rpc = env.rpc_client();
101+
let _ = env.mine_blocks(100, None);
102+
assert_eq!(rpc.get_block_count()?, 101);
103+
104+
let utxo = rpc.list_unspent(None, None, None, None, None)?[0].clone();
105+
106+
// Create tx1
107+
let utxos = vec![CreateRawTransactionInput {
108+
txid: utxo.txid,
109+
vout: utxo.vout,
110+
sequence: None,
111+
}];
112+
let to_send = Amount::ONE_BTC;
113+
let fee = Amount::from_sat(1_000);
114+
let change_addr = rpc.get_new_address(None, None)?.assume_checked();
115+
let out = [
116+
(recv_addr.to_string(), to_send),
117+
(change_addr.to_string(), utxo.amount - to_send - fee),
118+
]
119+
.into();
120+
let tx = rpc.create_raw_transaction(&utxos, &out, None, None)?;
121+
let tx1 = rpc
122+
.sign_raw_transaction_with_wallet(&tx, None, None)?
123+
.transaction()?;
124+
125+
// Create tx2 the double spend
126+
let new_addr = rpc.get_new_address(None, None)?.assume_checked();
127+
let out = [
128+
(new_addr.to_string(), to_send),
129+
(change_addr.to_string(), utxo.amount - to_send - (fee * 2)),
130+
]
131+
.into();
132+
let tx = rpc.create_raw_transaction(&utxos, &out, None, None)?;
133+
let tx2 = rpc
134+
.sign_raw_transaction_with_wallet(&tx, None, None)?
135+
.transaction()?;
136+
137+
// Sync after send tx 1
138+
let txid1 = rpc.send_raw_transaction(&tx1)?;
139+
println!("Send tx1 {}", txid1);
140+
141+
let base_url = format!("http://{}", &env.electrsd.esplora_url.clone().unwrap());
142+
let client = esplora_client::Builder::new(base_url.as_str()).build_async()?;
143+
144+
while client.get_height().await? < 101 {
145+
std::thread::sleep(std::time::Duration::from_millis(64));
146+
}
147+
env.wait_until_electrum_sees_txid(txid1, std::time::Duration::from_secs(10))?;
67148

68-
let balance = wallet.balance();
69-
println!("Wallet balance after syncing: {}", balance.total());
149+
let request = wallet.start_sync_with_revealed_spks();
70150

71-
if balance.total() < SEND_AMOUNT {
72-
println!(
73-
"Please send at least {} to the receiving address",
74-
SEND_AMOUNT
75-
);
76-
std::process::exit(0);
77-
}
151+
let resp = client.sync(request, PARALLEL_REQUESTS).await?;
152+
assert_eq!(resp.tx_update.txs.first().unwrap().compute_txid(), txid1);
78153

79-
let mut tx_builder = wallet.build_tx();
80-
tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);
154+
wallet.apply_update(resp)?;
155+
wallet.persist(&mut conn)?;
81156

82-
let mut psbt = tx_builder.finish()?;
83-
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
84-
assert!(finalized);
157+
assert_eq!(wallet.balance().total(), Amount::ONE_BTC);
158+
println!("Balance after send tx1: {}", wallet.balance().total());
159+
// We should expect tx1 to occur in a future sync
160+
let exp_spk_txids = wallet
161+
.tx_graph()
162+
.list_expected_spk_txids(
163+
wallet.local_chain(),
164+
wallet.local_chain().tip().block_id(),
165+
wallet.spk_index(),
166+
/*spk_index_range: */ ..,
167+
)
168+
.collect::<Vec<_>>();
169+
assert_eq!(
170+
exp_spk_txids.first(),
171+
Some(&(recv_addr.script_pubkey(), txid1))
172+
);
173+
174+
// Now sync after send tx 2
175+
let txid2 = rpc.send_raw_transaction(&tx2)?;
176+
println!("Send tx2 {}", txid2);
177+
env.wait_until_electrum_sees_txid(txid2, std::time::Duration::from_secs(10))?;
178+
179+
let request = wallet.start_sync_with_revealed_spks();
180+
181+
let resp = client.sync(request, PARALLEL_REQUESTS).await?;
182+
assert!(resp.tx_update.txs.is_empty());
183+
assert!(resp
184+
.tx_update
185+
.evicted_ats
186+
.iter()
187+
.any(|&(txid, _)| txid == txid1));
188+
189+
wallet.apply_update(resp)?;
190+
wallet.persist(&mut conn)?;
85191

86-
let tx = psbt.extract_tx()?;
87-
client.broadcast(&tx).await?;
88-
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
192+
println!("Balance after send tx2: {}", wallet.balance().total());
193+
assert_eq!(wallet.balance().total(), Amount::ZERO);
194+
195+
// Load the persisted wallet
196+
{
197+
wallet = Wallet::load()
198+
.load_wallet(&mut conn)?
199+
.expect("wallet was persisted");
200+
201+
// tx1 is there, but is not canonical
202+
assert!(wallet.tx_graph().full_txs().any(|node| node.txid == txid1));
203+
assert!(wallet
204+
.tx_graph()
205+
.list_canonical_txs(wallet.local_chain(), wallet.local_chain().tip().block_id())
206+
.next()
207+
.is_none());
208+
assert!(wallet.list_unspent().next().is_none());
209+
assert_eq!(wallet.balance().total(), Amount::ZERO);
210+
println!("Balance after load wallet: {}", wallet.balance().total());
211+
}
89212

90213
Ok(())
91214
}

examples/example_wallet_esplora_blocking/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ publish = false
88

99
[dependencies]
1010
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
11-
bdk_esplora = { version = "0.20", features = ["blocking"] }
11+
#bdk_esplora = { version = "0.20", features = ["blocking"] }
12+
bdk_esplora = { git = "https://github.com/bitcoindevkit/bdk", rev = "b70758652d1c819c88d92765905d09e26b951ee2", features = ["blocking"] }
1213
anyhow = "1"

examples/example_wallet_esplora_blocking/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7
1919
const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
2020

2121
fn main() -> Result<(), anyhow::Error> {
22-
let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), DB_PATH)?;
22+
let (mut db, _) = Store::<bdk_wallet::ChangeSet>::load_or_create(DB_MAGIC.as_bytes(), DB_PATH)?;
2323

2424
let wallet_opt = Wallet::load()
2525
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))

examples/example_wallet_rpc/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ edition = "2021"
77

88
[dependencies]
99
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
10-
bdk_bitcoind_rpc = { version = "0.18" }
10+
#bdk_bitcoind_rpc = { version = "0.18" }
11+
bdk_bitcoind_rpc = { git = "https://github.com/bitcoindevkit/bdk", rev = "b70758652d1c819c88d92765905d09e26b951ee2" }
1112

1213
anyhow = "1"
1314
clap = { version = "4.5.17", features = ["derive", "env"] }

examples/example_wallet_rpc/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ fn main() -> anyhow::Result<()> {
8686
);
8787

8888
let start_load_wallet = Instant::now();
89-
let mut db =
90-
Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), args.db_path)?;
89+
let (mut db, _) =
90+
Store::<bdk_wallet::ChangeSet>::load_or_create(DB_MAGIC.as_bytes(), args.db_path)?;
9191
let wallet_opt = Wallet::load()
9292
.descriptor(KeychainKind::External, Some(args.descriptor.clone()))
9393
.descriptor(KeychainKind::Internal, args.change_descriptor.clone())

wallet/Cargo.toml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,23 @@ miniscript = { version = "12.3.1", features = [ "serde" ], default-features = fa
2121
bitcoin = { version = "0.32.4", features = [ "serde", "base64" ], default-features = false }
2222
serde = { version = "^1.0", features = ["derive"] }
2323
serde_json = { version = "^1.0" }
24-
bdk_chain = { version = "0.21.1", features = [ "miniscript", "serde" ], default-features = false }
25-
bdk_file_store = { version = "0.18.1", optional = true }
24+
#bdk_chain = { version = "0.21.1", features = [ "miniscript", "serde" ], default-features = false }
25+
#bdk_file_store = { version = "0.18.1", optional = true }
2626

2727
# Optional dependencies
2828
bip39 = { version = "2.0", optional = true }
2929

30+
[dependencies.bdk_chain]
31+
git = "https://github.com/bitcoindevkit/bdk"
32+
rev = "b70758652d1c819c88d92765905d09e26b951ee2"
33+
default-features = false
34+
features = ["miniscript", "serde"]
35+
36+
[dependencies.bdk_file_store]
37+
git = "https://github.com/bitcoindevkit/bdk"
38+
rev = "b70758652d1c819c88d92765905d09e26b951ee2"
39+
optional = true
40+
3041
[features]
3142
default = ["std"]
3243
std = ["bitcoin/std", "bitcoin/rand-std", "miniscript/std", "bdk_chain/std"]
@@ -41,12 +52,17 @@ test-utils = ["std"]
4152
lazy_static = "1.4"
4253
assert_matches = "1.5.0"
4354
tempfile = "3"
44-
bdk_chain = { version = "0.21.1", features = ["rusqlite"] }
55+
#bdk_chain = { version = "0.21.1", features = ["rusqlite"] }
4556
bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] }
46-
bdk_file_store = { version = "0.18.1" }
57+
#bdk_file_store = { version = "0.18.1" }
4758
anyhow = "1"
4859
rand = "^0.8"
4960

61+
[dev-dependencies.bdk_chain]
62+
git = "https://github.com/bitcoindevkit/bdk"
63+
rev = "b70758652d1c819c88d92765905d09e26b951ee2"
64+
features = ["rusqlite"]
65+
5066
[package.metadata.docs.rs]
5167
all-features = true
5268
rustdoc-args = ["--cfg", "docsrs"]

wallet/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,12 @@ To persist `Wallet` state data use a data store crate that reads and writes [`Ch
6565

6666
**Example**
6767

68-
<!-- compile_fail because outpoint and txout are fake variables -->
6968
```rust,no_run
7069
use bdk_wallet::{bitcoin::Network, KeychainKind, ChangeSet, Wallet};
7170
7271
// Open or create a new file store for wallet data.
73-
let mut db =
74-
bdk_file_store::Store::<ChangeSet>::open_or_create_new(b"magic_bytes", "/tmp/my_wallet.db")
72+
let (mut db, _changeset) =
73+
bdk_file_store::Store::<ChangeSet>::load_or_create(b"magic_bytes", "/tmp/my_wallet.db")
7574
.expect("create store");
7675
7776
// Create a wallet with initial wallet data read from the file store.

0 commit comments

Comments
 (0)