Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions crates/chain/src/indexer/keychain_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,33 +973,35 @@ pub enum InsertDescriptorError<K> {
},
}

impl<K: core::fmt::Debug> core::fmt::Display for InsertDescriptorError<K> {
impl<K: core::fmt::Display> core::fmt::Display for InsertDescriptorError<K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
InsertDescriptorError::DescriptorAlreadyAssigned {
existing_assignment: existing,
existing_assignment,
descriptor,
} => {
write!(
f,
"attempt to re-assign descriptor {descriptor:?} already assigned to {existing:?}"
"descriptor '{}' is already in use by another keychain '{}'",
descriptor, existing_assignment
)
}
InsertDescriptorError::KeychainAlreadyAssigned {
existing_assignment: existing,
existing_assignment,
keychain,
} => {
write!(
f,
"attempt to re-assign keychain {keychain:?} already assigned to {existing:?}"
"keychain '{}' is already associated with another descriptor '{}'",
keychain, existing_assignment
)
}
}
}
}

#[cfg(feature = "std")]
impl<K: core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
impl<K: core::fmt::Display + core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
Comment thread
evanlinjin marked this conversation as resolved.

/// `ChangeSet` represents persistent updates to a [`KeychainTxOutIndex`].
///
Expand Down
36 changes: 27 additions & 9 deletions crates/chain/src/tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,33 @@ pub enum CalculateFeeError {
impl fmt::Display for CalculateFeeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
CalculateFeeError::MissingTxOut(outpoints) => write!(
f,
"missing `TxOut` for one or more of the inputs of the tx: {outpoints:?}",
),
CalculateFeeError::NegativeFee(fee) => write!(
f,
"transaction is invalid according to the graph and has negative fee: {}",
fee.display_dynamic()
),
CalculateFeeError::MissingTxOut(outpoints) => {
let max_show = 3;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I were to nit-pick, I would say get rid of this and just show all prev outputs.

let shown: Vec<_> = outpoints.iter().take(max_show).collect();
let remaining = outpoints.len().saturating_sub(max_show);

write!(f, "cannot calculate fee, missing previous output(s): ")?;
if outpoints.is_empty() {
write!(f, "<none>")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this ever happens, it's a bug in the library - let's debug_assert! it?

} else {
write!(f, "{}", shown[0])?;
for op in &shown[1..] {
write!(f, ", {}", op)?;
}
if remaining > 0 {
write!(f, " (+{} more)", remaining)?;
}
Comment thread
Dmenec marked this conversation as resolved.
Ok(())
}
}
CalculateFeeError::NegativeFee(fee) => {
write!(
f,
"invalid transaction: negative fee {}",
fee.display_dynamic()
)?;
Ok(())
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions crates/chain/tests/test_keychain_txout_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ enum TestKeychain {
Internal,
}

impl core::fmt::Display for TestKeychain {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
TestKeychain::External => write!(f, "External"),
TestKeychain::Internal => write!(f, "Internal"),
}
}
}

fn parse_descriptor(descriptor: &str) -> Descriptor<DescriptorPublicKey> {
let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, descriptor)
Expand Down
18 changes: 17 additions & 1 deletion crates/core/src/spk_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ impl<I, D> SyncRequestBuilder<I, D> {
/// [`chain_tip`](SyncRequestBuilder::chain_tip) (if provided).
///
/// ```rust
/// # use std::io::{self, Write};
/// # use bdk_chain::{bitcoin::{hashes::Hash, ScriptBuf}, local_chain::LocalChain};
/// # use bdk_chain::spk_client::SyncRequest;
/// # let (local_chain, _) = LocalChain::from_genesis(Hash::all_zeros());
Expand All @@ -236,7 +237,22 @@ impl<I, D> SyncRequestBuilder<I, D> {
/// // Provide list of scripts to scan for transactions against.
/// .spks(scripts)
/// // This is called for every synced item.
/// .inspect(|item, progress| println!("{} (remaining: {})", item, progress.remaining()))
/// .inspect(|item, progress| {
/// let pc = (100.0 * progress.consumed() as f32) / progress.total() as f32;
/// match item {
/// // In this example I = (), so the first field of Spk is unit.
/// bdk_chain::spk_client::SyncItem::Spk((), spk) => {
/// eprintln!("[ SCANNING {pc:03.0}% ] script {}", spk);
/// }
/// bdk_chain::spk_client::SyncItem::Txid(txid) => {
/// eprintln!("[ SCANNING {pc:03.0}% ] txid {}", txid);
/// }
/// bdk_chain::spk_client::SyncItem::OutPoint(op) => {
/// eprintln!("[ SCANNING {pc:03.0}% ] outpoint {}", op);
/// }
/// }
/// let _ = io::stderr().flush();
/// })
/// // Finish constructing the sync request.
/// .build();
/// ```
Expand Down
23 changes: 17 additions & 6 deletions crates/file_store/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ pub enum StoreError {

impl core::fmt::Display for StoreError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
fn fmt_hex_bytes(f: &mut core::fmt::Formatter<'_>, bytes: &[u8]) -> core::fmt::Result {
for &b in bytes {
write!(f, "{:02x}", b)?;
}
Ok(())
}

match self {
Self::Io(e) => write!(f, "io error trying to read file: {e}"),
Self::InvalidMagicBytes { got, expected } => write!(
f,
"file has invalid magic bytes: expected={expected:?} got={got:?}",
),
Self::Bincode(e) => write!(f, "bincode error while reading entry {e}"),
Self::Io(e) => write!(f, "io error while reading store file: {}", e),
Self::Bincode(e) => write!(f, "bincode error while decoding entry {}", e),
Self::InvalidMagicBytes { got, expected } => {
write!(f, "invalid magic bytes: ")?;
write!(f, "expected 0x")?;
fmt_hex_bytes(f, expected)?;
write!(f, ", got 0x")?;
fmt_hex_bytes(f, got)?;
Ok(())
}
}
}
}
Expand Down
17 changes: 15 additions & 2 deletions examples/example_electrum/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,22 @@ fn main() -> anyhow::Result<()> {
.chain_tip(chain_tip.clone())
.inspect(|item, progress| {
let pc = (100 * progress.consumed()) as f32 / progress.total() as f32;
eprintln!("[ SCANNING {pc:03.0}% ] {item}");
match item {
bdk_chain::spk_client::SyncItem::Spk((keychain, index), spk) => {
eprintln!(
"[ SCANNING {pc:3.0}% ] script {} {} {}",
keychain, index, spk
);
}
bdk_chain::spk_client::SyncItem::Txid(txid) => {
eprintln!("[ SCANNING {pc:3.0}% ] txid {}", txid);
}
bdk_chain::spk_client::SyncItem::OutPoint(op) => {
eprintln!("[ SCANNING {pc:3.0}% ] outpoint {}", op);
}
}
let _ = io::stderr().flush();
});

let canonical_view = graph.canonical_view(
&*chain,
chain_tip.block_id(),
Expand Down
16 changes: 14 additions & 2 deletions examples/example_esplora/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,20 @@ fn main() -> anyhow::Result<()> {
.chain_tip(local_tip.clone())
.inspect(|item, progress| {
let pc = (100 * progress.consumed()) as f32 / progress.total() as f32;
eprintln!("[ SCANNING {pc:03.0}% ] {item}");
// Flush early to ensure we print at every iteration.
match item {
bdk_chain::spk_client::SyncItem::Spk((keychain, index), spk) => {
eprintln!(
"[ SCANNING {pc:3.0}% ] script {} {} {}",
keychain, index, spk
);
}
bdk_chain::spk_client::SyncItem::Txid(txid) => {
eprintln!("[ SCANNING {pc:3.0}% ] txid {}", txid);
}
bdk_chain::spk_client::SyncItem::OutPoint(op) => {
eprintln!("[ SCANNING {pc:3.0}% ] outpoint {}", op);
}
}
let _ = io::stderr().flush();
});

Expand Down