feat(wallet)!: change persist API to use StageExt
and StageExtAsync
This commit is contained in:
parent
2e40b0118c
commit
19328d4999
@ -30,6 +30,7 @@ js-sys = "0.3"
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"]
|
std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"]
|
||||||
|
async = ["bdk_chain/async"]
|
||||||
compiler = ["miniscript/compiler"]
|
compiler = ["miniscript/compiler"]
|
||||||
all-keys = ["keys-bip39"]
|
all-keys = ["keys-bip39"]
|
||||||
keys-bip39 = ["bip39"]
|
keys-bip39 = ["bip39"]
|
||||||
|
@ -26,6 +26,7 @@ use bdk_chain::{
|
|||||||
local_chain::{
|
local_chain::{
|
||||||
self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain,
|
self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain,
|
||||||
},
|
},
|
||||||
|
persist::{PersistBackend, StageExt},
|
||||||
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
||||||
tx_graph::{CanonicalTx, TxGraph},
|
tx_graph::{CanonicalTx, TxGraph},
|
||||||
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
|
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
|
||||||
@ -40,7 +41,6 @@ use bitcoin::{
|
|||||||
use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt};
|
use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt};
|
||||||
use bitcoin::{constants::genesis_block, Amount};
|
use bitcoin::{constants::genesis_block, Amount};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::mem;
|
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use descriptor::error::Error as DescriptorError;
|
use descriptor::error::Error as DescriptorError;
|
||||||
use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier};
|
use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier};
|
||||||
@ -393,18 +393,6 @@ impl Wallet {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stage a ['ChangeSet'] to be persisted later.
|
|
||||||
///
|
|
||||||
/// [`commit`]: Self::commit
|
|
||||||
fn stage(&mut self, changeset: ChangeSet) {
|
|
||||||
self.stage.append(changeset)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take the staged [`ChangeSet`] to be persisted now.
|
|
||||||
pub fn take_staged(&mut self) -> ChangeSet {
|
|
||||||
mem::take(&mut self.stage)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load [`Wallet`] from the given previously persisted [`ChangeSet`].
|
/// Load [`Wallet`] from the given previously persisted [`ChangeSet`].
|
||||||
///
|
///
|
||||||
/// Note that the descriptor secret keys are not persisted to the db; this means that after
|
/// Note that the descriptor secret keys are not persisted to the db; this means that after
|
||||||
@ -687,7 +675,7 @@ impl Wallet {
|
|||||||
/// # let changeset = ChangeSet::default();
|
/// # let changeset = ChangeSet::default();
|
||||||
/// # let mut wallet = Wallet::load_from_changeset(changeset).expect("load wallet");
|
/// # let mut wallet = Wallet::load_from_changeset(changeset).expect("load wallet");
|
||||||
/// let next_address = wallet.reveal_next_address(KeychainKind::External);
|
/// let next_address = wallet.reveal_next_address(KeychainKind::External);
|
||||||
/// db.write_changes(&wallet.take_staged())?;
|
/// wallet.commit_to(&mut db)?;
|
||||||
///
|
///
|
||||||
/// // Now it's safe to show the user their next address!
|
/// // Now it's safe to show the user their next address!
|
||||||
/// println!("Next address: {}", next_address.address);
|
/// println!("Next address: {}", next_address.address);
|
||||||
@ -731,7 +719,7 @@ impl Wallet {
|
|||||||
.reveal_to_target(&keychain, index)
|
.reveal_to_target(&keychain, index)
|
||||||
.expect("keychain must exist");
|
.expect("keychain must exist");
|
||||||
|
|
||||||
self.stage(indexed_tx_graph::ChangeSet::from(index_changeset).into());
|
self.stage.append(index_changeset.into());
|
||||||
|
|
||||||
spks.into_iter().map(move |(index, spk)| AddressInfo {
|
spks.into_iter().map(move |(index, spk)| AddressInfo {
|
||||||
index,
|
index,
|
||||||
@ -915,7 +903,7 @@ impl Wallet {
|
|||||||
/// [`list_output`]: Self::list_output
|
/// [`list_output`]: Self::list_output
|
||||||
pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) {
|
pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) {
|
||||||
let additions = self.indexed_graph.insert_txout(outpoint, txout);
|
let additions = self.indexed_graph.insert_txout(outpoint, txout);
|
||||||
self.stage(ChangeSet::from(additions));
|
self.stage.append(additions.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction.
|
/// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction.
|
||||||
@ -1084,7 +1072,7 @@ impl Wallet {
|
|||||||
) -> Result<bool, local_chain::AlterCheckPointError> {
|
) -> Result<bool, local_chain::AlterCheckPointError> {
|
||||||
let changeset = self.chain.insert_block(block_id)?;
|
let changeset = self.chain.insert_block(block_id)?;
|
||||||
let changed = !changeset.is_empty();
|
let changed = !changeset.is_empty();
|
||||||
self.stage(changeset.into());
|
self.stage.append(changeset.into());
|
||||||
Ok(changed)
|
Ok(changed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1146,7 +1134,7 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let changed = !changeset.is_empty();
|
let changed = !changeset.is_empty();
|
||||||
self.stage(changeset);
|
self.stage.append(changeset);
|
||||||
Ok(changed)
|
Ok(changed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1470,9 +1458,7 @@ impl Wallet {
|
|||||||
.next_unused_spk(&change_keychain)
|
.next_unused_spk(&change_keychain)
|
||||||
.expect("keychain must exist");
|
.expect("keychain must exist");
|
||||||
self.indexed_graph.index.mark_used(change_keychain, index);
|
self.indexed_graph.index.mark_used(change_keychain, index);
|
||||||
self.stage(ChangeSet::from(indexed_tx_graph::ChangeSet::from(
|
self.stage.append(index_changeset.into());
|
||||||
index_changeset,
|
|
||||||
)));
|
|
||||||
spk
|
spk
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2291,16 +2277,52 @@ impl Wallet {
|
|||||||
.indexed_graph
|
.indexed_graph
|
||||||
.index
|
.index
|
||||||
.reveal_to_target_multi(&update.last_active_indices);
|
.reveal_to_target_multi(&update.last_active_indices);
|
||||||
changeset.append(ChangeSet::from(indexed_tx_graph::ChangeSet::from(
|
changeset.append(index_changeset.into());
|
||||||
index_changeset,
|
changeset.append(self.indexed_graph.apply_update(update.graph).into());
|
||||||
)));
|
self.stage.append(changeset);
|
||||||
changeset.append(ChangeSet::from(
|
|
||||||
self.indexed_graph.apply_update(update.graph),
|
|
||||||
));
|
|
||||||
self.stage(changeset);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Commits all currently [`staged`](Wallet::staged) changes to the `persist_backend`.
|
||||||
|
///
|
||||||
|
/// This returns whether anything was persisted.
|
||||||
|
///
|
||||||
|
/// # Error
|
||||||
|
///
|
||||||
|
/// Returns a backend-defined error if this fails.
|
||||||
|
pub fn commit_to<B>(&mut self, persist_backend: &mut B) -> Result<bool, B::WriteError>
|
||||||
|
where
|
||||||
|
B: PersistBackend<ChangeSet>,
|
||||||
|
{
|
||||||
|
let committed = StageExt::commit_to(&mut self.stage, persist_backend)?;
|
||||||
|
Ok(committed.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Commits all currently [`staged`](Wallet::staged) changes to the async `persist_backend`.
|
||||||
|
///
|
||||||
|
/// This returns whether anything was persisted.
|
||||||
|
///
|
||||||
|
/// # Error
|
||||||
|
///
|
||||||
|
/// Returns a backend-defined error if this fails.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub async fn commit_to_async<B>(
|
||||||
|
&mut self,
|
||||||
|
persist_backend: &mut B,
|
||||||
|
) -> Result<bool, B::WriteError>
|
||||||
|
where
|
||||||
|
B: bdk_chain::persist::PersistBackendAsync<ChangeSet> + Send + Sync,
|
||||||
|
{
|
||||||
|
let committed =
|
||||||
|
bdk_chain::persist::StageExtAsync::commit_to(&mut self.stage, persist_backend).await?;
|
||||||
|
Ok(committed.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the staged [`ChangeSet`] that is yet to be committed.
|
||||||
|
pub fn staged(&self) -> &ChangeSet {
|
||||||
|
&self.stage
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the inner [`TxGraph`].
|
/// Get a reference to the inner [`TxGraph`].
|
||||||
pub fn tx_graph(&self) -> &TxGraph<ConfirmationTimeHeightAnchor> {
|
pub fn tx_graph(&self) -> &TxGraph<ConfirmationTimeHeightAnchor> {
|
||||||
self.indexed_graph.graph()
|
self.indexed_graph.graph()
|
||||||
@ -2370,7 +2392,7 @@ impl Wallet {
|
|||||||
.apply_block_relevant(block, height)
|
.apply_block_relevant(block, height)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
self.stage(changeset);
|
self.stage.append(changeset);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2393,7 +2415,7 @@ impl Wallet {
|
|||||||
let indexed_graph_changeset = self
|
let indexed_graph_changeset = self
|
||||||
.indexed_graph
|
.indexed_graph
|
||||||
.batch_insert_relevant_unconfirmed(unconfirmed_txs);
|
.batch_insert_relevant_unconfirmed(unconfirmed_txs);
|
||||||
self.stage(ChangeSet::from(indexed_graph_changeset));
|
self.stage.append(indexed_graph_changeset.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +90,10 @@ fn load_recovers_wallet() -> anyhow::Result<()> {
|
|||||||
wallet.reveal_next_address(KeychainKind::External);
|
wallet.reveal_next_address(KeychainKind::External);
|
||||||
|
|
||||||
// persist new wallet changes
|
// persist new wallet changes
|
||||||
let staged_changeset = wallet.take_staged();
|
let mut db = create_new(&file_path).expect("must create db");
|
||||||
let db = &mut create_new(&file_path).expect("must create db");
|
wallet
|
||||||
db.write_changes(&staged_changeset)
|
.commit_to(&mut db)
|
||||||
.map_err(|e| anyhow!("write changes error: {}", e))?;
|
.map_err(|e| anyhow!("write changes error: {}", e))?;
|
||||||
|
|
||||||
wallet.spk_index().clone()
|
wallet.spk_index().clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,9 +157,9 @@ fn new_or_load() -> anyhow::Result<()> {
|
|||||||
let wallet_keychains: BTreeMap<_, _> = {
|
let wallet_keychains: BTreeMap<_, _> = {
|
||||||
let wallet = &mut Wallet::new_or_load(desc, change_desc, None, Network::Testnet)
|
let wallet = &mut Wallet::new_or_load(desc, change_desc, None, Network::Testnet)
|
||||||
.expect("must init wallet");
|
.expect("must init wallet");
|
||||||
let staged_changeset = wallet.take_staged();
|
|
||||||
let mut db = new_or_load(&file_path).expect("must create db");
|
let mut db = new_or_load(&file_path).expect("must create db");
|
||||||
db.write_changes(&staged_changeset)
|
wallet
|
||||||
|
.commit_to(&mut db)
|
||||||
.map_err(|e| anyhow!("write changes error: {}", e))?;
|
.map_err(|e| anyhow!("write changes error: {}", e))?;
|
||||||
wallet.keychains().map(|(k, v)| (*k, v.clone())).collect()
|
wallet.keychains().map(|(k, v)| (*k, v.clone())).collect()
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let address = wallet.next_unused_address(KeychainKind::External);
|
let address = wallet.next_unused_address(KeychainKind::External);
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!("Generated Address: {}", address);
|
println!("Generated Address: {}", address);
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
@ -72,7 +72,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
println!();
|
println!();
|
||||||
|
|
||||||
wallet.apply_update(update)?;
|
wallet.apply_update(update)?;
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
println!("Wallet balance after syncing: {} sats", balance.total());
|
println!("Wallet balance after syncing: {} sats", balance.total());
|
||||||
|
@ -30,7 +30,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let address = wallet.next_unused_address(KeychainKind::External);
|
let address = wallet.next_unused_address(KeychainKind::External);
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!("Generated Address: {}", address);
|
println!("Generated Address: {}", address);
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
@ -78,7 +78,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
|||||||
let _ = update.graph_update.update_last_seen_unconfirmed(now);
|
let _ = update.graph_update.update_last_seen_unconfirmed(now);
|
||||||
|
|
||||||
wallet.apply_update(update)?;
|
wallet.apply_update(update)?;
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
|
@ -29,7 +29,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let address = wallet.next_unused_address(KeychainKind::External);
|
let address = wallet.next_unused_address(KeychainKind::External);
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!("Generated Address: {}", address);
|
println!("Generated Address: {}", address);
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
@ -55,7 +55,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||||||
let _ = update.graph_update.update_last_seen_unconfirmed(now);
|
let _ = update.graph_update.update_last_seen_unconfirmed(now);
|
||||||
|
|
||||||
wallet.apply_update(update)?;
|
wallet.apply_update(update)?;
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
let balance = wallet.balance();
|
let balance = wallet.balance();
|
||||||
|
@ -147,7 +147,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let connected_to = block_emission.connected_to();
|
let connected_to = block_emission.connected_to();
|
||||||
let start_apply_block = Instant::now();
|
let start_apply_block = Instant::now();
|
||||||
wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
|
wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
let elapsed = start_apply_block.elapsed().as_secs_f32();
|
let elapsed = start_apply_block.elapsed().as_secs_f32();
|
||||||
println!(
|
println!(
|
||||||
"Applied block {} at height {} in {}s",
|
"Applied block {} at height {} in {}s",
|
||||||
@ -157,7 +157,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
Emission::Mempool(mempool_emission) => {
|
Emission::Mempool(mempool_emission) => {
|
||||||
let start_apply_mempool = Instant::now();
|
let start_apply_mempool = Instant::now();
|
||||||
wallet.apply_unconfirmed_txs(mempool_emission.iter().map(|(tx, time)| (tx, *time)));
|
wallet.apply_unconfirmed_txs(mempool_emission.iter().map(|(tx, time)| (tx, *time)));
|
||||||
db.write_changes(&wallet.take_staged())?;
|
wallet.commit_to(&mut db)?;
|
||||||
println!(
|
println!(
|
||||||
"Applied unconfirmed transactions in {}s",
|
"Applied unconfirmed transactions in {}s",
|
||||||
start_apply_mempool.elapsed().as_secs_f32()
|
start_apply_mempool.elapsed().as_secs_f32()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user