Merge bitcoindevkit/bdk#1084: Enhance bdk chain structures
1ff806c67ffix(chain)!: rm weird `From` impl (志宇)d43ae0231frefactor: improve docs, cleanup unnecessary types and improve code (Vladimir Fomene)4104206980feat: impl Append for lots of tuples (LLFourn)c56728ff13refactor: Remove `scan` and `scan_txout` from SpkTxoutIndex and KeychainTxoutIndex (Vladimir Fomene)32c40ac939feat(electrum)!: change signature of `ElectrumExt` (志宇)a28748c339refactor: Implement Default for WalletUpdate (Vladimir Fomene)f42f8b8ff1refactor: Allow for no chain update (Vladimir Fomene)68572bfd2erefactor: move WalletChangeset to wallet module (Vladimir Fomene)2392e50fd9refactor: Move WalletUpdate to wallet module (Vladimir Fomene)7c12dc9942refactor: Remove ForEachTxout trait (Vladimir Fomene)6bcbb93233refactor: Edit ElectrumExt not to use WalletUpdate (Vladimir Fomene) Pull request description: ### Description Fixes #1061 ### Changelog notice - Move WalletUpdate to the wallet module - Remove ForEachTxout trait completely - Refactor ElectrumExt to not use WalletUpdate. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing ACKs for top commit: evanlinjin: ACK1ff806c67fTree-SHA512: 05349713af9d2efa14a522ceaabb7513bb437d786adf2f93055765589a67e4eb68bda36ff415aeba07816c4d30988d4d55bac018e7697019270a219105ed65a2
This commit is contained in:
@@ -12,6 +12,7 @@ use bdk_chain::{
|
||||
},
|
||||
indexed_tx_graph::{self, IndexedTxGraph},
|
||||
keychain::{self, KeychainTxOutIndex},
|
||||
local_chain,
|
||||
miniscript::{
|
||||
descriptor::{DescriptorSecretKey, KeyMap},
|
||||
Descriptor, DescriptorPublicKey,
|
||||
@@ -24,7 +25,10 @@ pub use clap;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
pub type KeychainTxGraph<A> = IndexedTxGraph<A, KeychainTxOutIndex<Keychain>>;
|
||||
pub type KeychainChangeSet<A> = indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<Keychain>>;
|
||||
pub type KeychainChangeSet<A> = (
|
||||
local_chain::ChangeSet,
|
||||
indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<Keychain>>,
|
||||
);
|
||||
pub type Database<'m, C> = Persist<Store<'m, C>, C>;
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -200,7 +204,10 @@ where
|
||||
|
||||
let ((spk_i, spk), index_changeset) = spk_chooser(index, &Keychain::External);
|
||||
let db = &mut *db.lock().unwrap();
|
||||
db.stage(C::from(KeychainChangeSet::from(index_changeset)));
|
||||
db.stage(C::from((
|
||||
local_chain::ChangeSet::default(),
|
||||
indexed_tx_graph::ChangeSet::from(index_changeset),
|
||||
)));
|
||||
db.commit()?;
|
||||
let addr = Address::from_script(spk, network).context("failed to derive address")?;
|
||||
println!("[address @ {}] {}", spk_i, addr);
|
||||
@@ -353,7 +360,10 @@ where
|
||||
// If we're unable to persist this, then we don't want to broadcast.
|
||||
{
|
||||
let db = &mut *db.lock().unwrap();
|
||||
db.stage(C::from(KeychainChangeSet::from(index_changeset)));
|
||||
db.stage(C::from((
|
||||
local_chain::ChangeSet::default(),
|
||||
indexed_tx_graph::ChangeSet::from(index_changeset),
|
||||
)));
|
||||
db.commit()?;
|
||||
}
|
||||
|
||||
@@ -376,7 +386,10 @@ where
|
||||
// We know the tx is at least unconfirmed now. Note if persisting here fails,
|
||||
// it's not a big deal since we can always find it again form
|
||||
// blockchain.
|
||||
db.lock().unwrap().stage(C::from(keychain_changeset));
|
||||
db.lock().unwrap().stage(C::from((
|
||||
local_chain::ChangeSet::default(),
|
||||
keychain_changeset,
|
||||
)));
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -7,8 +7,8 @@ use std::{
|
||||
use bdk_chain::{
|
||||
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
|
||||
indexed_tx_graph::{self, IndexedTxGraph},
|
||||
keychain::WalletChangeSet,
|
||||
local_chain::LocalChain,
|
||||
keychain,
|
||||
local_chain::{self, LocalChain},
|
||||
Append, ConfirmationHeightAnchor,
|
||||
};
|
||||
use bdk_electrum::{
|
||||
@@ -60,19 +60,22 @@ pub struct ScanOptions {
|
||||
pub batch_size: usize,
|
||||
}
|
||||
|
||||
type ChangeSet = WalletChangeSet<Keychain, ConfirmationHeightAnchor>;
|
||||
type ChangeSet = (
|
||||
local_chain::ChangeSet,
|
||||
indexed_tx_graph::ChangeSet<ConfirmationHeightAnchor, keychain::ChangeSet<Keychain>>,
|
||||
);
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let (args, keymap, index, db, init_changeset) =
|
||||
let (args, keymap, index, db, (disk_local_chain, disk_tx_graph)) =
|
||||
example_cli::init::<ElectrumCommands, ChangeSet>(DB_MAGIC, DB_PATH)?;
|
||||
|
||||
let graph = Mutex::new({
|
||||
let mut graph = IndexedTxGraph::new(index);
|
||||
graph.apply_changeset(init_changeset.indexed_tx_graph);
|
||||
graph.apply_changeset(disk_tx_graph);
|
||||
graph
|
||||
});
|
||||
|
||||
let chain = Mutex::new(LocalChain::from_changeset(init_changeset.chain));
|
||||
let chain = Mutex::new(LocalChain::from_changeset(disk_local_chain));
|
||||
|
||||
let electrum_url = match args.network {
|
||||
Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
|
||||
@@ -248,20 +251,24 @@ fn main() -> anyhow::Result<()> {
|
||||
// drop lock on graph and chain
|
||||
drop((graph, chain));
|
||||
|
||||
let update = client
|
||||
let electrum_update = client
|
||||
.scan_without_keychain(tip, spks, txids, outpoints, scan_options.batch_size)
|
||||
.context("scanning the blockchain")?;
|
||||
ElectrumUpdate {
|
||||
graph_update: update.graph_update,
|
||||
new_tip: update.new_tip,
|
||||
keychain_update: BTreeMap::new(),
|
||||
}
|
||||
(electrum_update, BTreeMap::new())
|
||||
}
|
||||
};
|
||||
|
||||
let (
|
||||
ElectrumUpdate {
|
||||
chain_update,
|
||||
relevant_txids,
|
||||
},
|
||||
keychain_update,
|
||||
) = response;
|
||||
|
||||
let missing_txids = {
|
||||
let graph = &*graph.lock().unwrap();
|
||||
response.missing_full_txs(graph.graph())
|
||||
relevant_txids.missing_full_txs(graph.graph())
|
||||
};
|
||||
|
||||
let now = std::time::UNIX_EPOCH
|
||||
@@ -269,32 +276,27 @@ fn main() -> anyhow::Result<()> {
|
||||
.expect("must get time")
|
||||
.as_secs();
|
||||
|
||||
let final_update = response.finalize(&client, Some(now), missing_txids)?;
|
||||
let graph_update = relevant_txids.into_tx_graph(&client, Some(now), missing_txids)?;
|
||||
|
||||
let db_changeset = {
|
||||
let mut chain = chain.lock().unwrap();
|
||||
let mut graph = graph.lock().unwrap();
|
||||
|
||||
let chain = chain.apply_update(final_update.chain)?;
|
||||
let chain = chain.apply_update(chain_update)?;
|
||||
|
||||
let indexed_tx_graph = {
|
||||
let mut changeset =
|
||||
indexed_tx_graph::ChangeSet::<ConfirmationHeightAnchor, _>::default();
|
||||
let (_, indexer) = graph
|
||||
.index
|
||||
.reveal_to_target_multi(&final_update.last_active_indices);
|
||||
let (_, indexer) = graph.index.reveal_to_target_multi(&keychain_update);
|
||||
changeset.append(indexed_tx_graph::ChangeSet {
|
||||
indexer,
|
||||
..Default::default()
|
||||
});
|
||||
changeset.append(graph.apply_update(final_update.graph));
|
||||
changeset.append(graph.apply_update(graph_update));
|
||||
changeset
|
||||
};
|
||||
|
||||
ChangeSet {
|
||||
indexed_tx_graph,
|
||||
chain,
|
||||
}
|
||||
(chain, indexed_tx_graph)
|
||||
};
|
||||
|
||||
let mut db = db.lock().unwrap();
|
||||
|
||||
@@ -6,9 +6,9 @@ use std::{
|
||||
|
||||
use bdk_chain::{
|
||||
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
|
||||
indexed_tx_graph::IndexedTxGraph,
|
||||
keychain::WalletChangeSet,
|
||||
local_chain::{CheckPoint, LocalChain},
|
||||
indexed_tx_graph::{self, IndexedTxGraph},
|
||||
keychain,
|
||||
local_chain::{self, CheckPoint, LocalChain},
|
||||
Append, ConfirmationTimeAnchor,
|
||||
};
|
||||
|
||||
@@ -23,6 +23,11 @@ use example_cli::{
|
||||
const DB_MAGIC: &[u8] = b"bdk_example_esplora";
|
||||
const DB_PATH: &str = ".bdk_esplora_example.db";
|
||||
|
||||
type ChangeSet = (
|
||||
local_chain::ChangeSet,
|
||||
indexed_tx_graph::ChangeSet<ConfirmationTimeAnchor, keychain::ChangeSet<Keychain>>,
|
||||
);
|
||||
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
enum EsploraCommands {
|
||||
/// Scans the addresses in the wallet using the esplora API.
|
||||
@@ -60,22 +65,22 @@ pub struct ScanOptions {
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let (args, keymap, index, db, init_changeset) = example_cli::init::<
|
||||
EsploraCommands,
|
||||
WalletChangeSet<Keychain, ConfirmationTimeAnchor>,
|
||||
>(DB_MAGIC, DB_PATH)?;
|
||||
let (args, keymap, index, db, init_changeset) =
|
||||
example_cli::init::<EsploraCommands, ChangeSet>(DB_MAGIC, DB_PATH)?;
|
||||
|
||||
let (init_chain_changeset, init_indexed_tx_graph_changeset) = init_changeset;
|
||||
|
||||
// Contruct `IndexedTxGraph` and `LocalChain` with our initial changeset. They are wrapped in
|
||||
// `Mutex` to display how they can be used in a multithreaded context. Technically the mutexes
|
||||
// aren't strictly needed here.
|
||||
let graph = Mutex::new({
|
||||
let mut graph = IndexedTxGraph::new(index);
|
||||
graph.apply_changeset(init_changeset.indexed_tx_graph);
|
||||
graph.apply_changeset(init_indexed_tx_graph_changeset);
|
||||
graph
|
||||
});
|
||||
let chain = Mutex::new({
|
||||
let mut chain = LocalChain::default();
|
||||
chain.apply_changeset(&init_changeset.chain);
|
||||
chain.apply_changeset(&init_chain_changeset);
|
||||
chain
|
||||
});
|
||||
|
||||
@@ -303,18 +308,17 @@ fn main() -> anyhow::Result<()> {
|
||||
println!("missing block heights: {:?}", missing_block_heights);
|
||||
|
||||
// Here, we actually fetch the missing blocks and create a `local_chain::Update`.
|
||||
let chain_update = client
|
||||
.update_local_chain(tip, missing_block_heights)
|
||||
.context("scanning for blocks")?;
|
||||
|
||||
println!("new tip: {}", chain_update.tip.height());
|
||||
let chain_changeset = {
|
||||
let chain_update = client
|
||||
.update_local_chain(tip, missing_block_heights)
|
||||
.context("scanning for blocks")?;
|
||||
println!("new tip: {}", chain_update.tip.height());
|
||||
chain.lock().unwrap().apply_update(chain_update)?
|
||||
};
|
||||
|
||||
// We persist the changes
|
||||
let mut db = db.lock().unwrap();
|
||||
db.stage(WalletChangeSet {
|
||||
chain: chain.lock().unwrap().apply_update(chain_update)?,
|
||||
indexed_tx_graph: indexed_tx_graph_changeset,
|
||||
});
|
||||
db.stage((chain_changeset, indexed_tx_graph_changeset));
|
||||
db.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@ use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use bdk::bitcoin::Address;
|
||||
use bdk::wallet::Update;
|
||||
use bdk::SignOptions;
|
||||
use bdk::{bitcoin::Network, Wallet};
|
||||
use bdk_electrum::electrum_client::{self, ElectrumApi};
|
||||
use bdk_electrum::ElectrumExt;
|
||||
use bdk_electrum::{
|
||||
electrum_client::{self, ElectrumApi},
|
||||
ElectrumExt, ElectrumUpdate,
|
||||
};
|
||||
use bdk_file_store::Store;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -52,14 +55,25 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let electrum_update = client.scan(prev_tip, keychain_spks, None, None, STOP_GAP, BATCH_SIZE)?;
|
||||
let (
|
||||
ElectrumUpdate {
|
||||
chain_update,
|
||||
relevant_txids,
|
||||
},
|
||||
keychain_update,
|
||||
) = client.scan(prev_tip, keychain_spks, None, None, STOP_GAP, BATCH_SIZE)?;
|
||||
|
||||
println!();
|
||||
|
||||
let missing = electrum_update.missing_full_txs(wallet.as_ref());
|
||||
let update = electrum_update.finalize_as_confirmation_time(&client, None, missing)?;
|
||||
let missing = relevant_txids.missing_full_txs(wallet.as_ref());
|
||||
let graph_update = relevant_txids.into_confirmation_time_tx_graph(&client, None, missing)?;
|
||||
|
||||
wallet.apply_update(update)?;
|
||||
let wallet_update = Update {
|
||||
last_active_indices: keychain_update,
|
||||
graph: graph_update,
|
||||
chain: Some(chain_update),
|
||||
};
|
||||
wallet.apply_update(wallet_update)?;
|
||||
wallet.commit()?;
|
||||
|
||||
let balance = wallet.get_balance();
|
||||
|
||||
@@ -2,8 +2,7 @@ use std::{io::Write, str::FromStr};
|
||||
|
||||
use bdk::{
|
||||
bitcoin::{Address, Network},
|
||||
chain::keychain::WalletUpdate,
|
||||
wallet::AddressIndex,
|
||||
wallet::{AddressIndex, Update},
|
||||
SignOptions, Wallet,
|
||||
};
|
||||
use bdk_esplora::{esplora_client, EsploraAsyncExt};
|
||||
@@ -59,10 +58,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.await?;
|
||||
let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
|
||||
let chain_update = client.update_local_chain(prev_tip, missing_heights).await?;
|
||||
let update = WalletUpdate {
|
||||
let update = Update {
|
||||
last_active_indices,
|
||||
graph: update_graph,
|
||||
..WalletUpdate::new(chain_update)
|
||||
chain: Some(chain_update),
|
||||
};
|
||||
wallet.apply_update(update)?;
|
||||
wallet.commit()?;
|
||||
|
||||
@@ -7,8 +7,7 @@ use std::{io::Write, str::FromStr};
|
||||
|
||||
use bdk::{
|
||||
bitcoin::{Address, Network},
|
||||
chain::keychain::WalletUpdate,
|
||||
wallet::AddressIndex,
|
||||
wallet::{AddressIndex, Update},
|
||||
SignOptions, Wallet,
|
||||
};
|
||||
use bdk_esplora::{esplora_client, EsploraExt};
|
||||
@@ -58,10 +57,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
client.scan_txs_with_keychains(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS)?;
|
||||
let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
|
||||
let chain_update = client.update_local_chain(prev_tip, missing_heights)?;
|
||||
let update = WalletUpdate {
|
||||
let update = Update {
|
||||
last_active_indices,
|
||||
graph: update_graph,
|
||||
..WalletUpdate::new(chain_update)
|
||||
chain: Some(chain_update),
|
||||
};
|
||||
|
||||
wallet.apply_update(update)?;
|
||||
|
||||
Reference in New Issue
Block a user