Skip to content
Open
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
2 changes: 1 addition & 1 deletion key-wallet-manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub mod wallet_manager;
// Re-export key-wallet types
pub use key_wallet::{
Account, AccountType, Address, AddressType, ChildNumber, DerivationPath, ExtendedPrivKey,
ExtendedPubKey, Mnemonic, Network, Utxo, UtxoSet, Wallet,
ExtendedPubKey, Mnemonic, Network, Utxo, Wallet,
};

// Re-export dashcore transaction types
Expand Down
2 changes: 1 addition & 1 deletion key-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub use managed_account::managed_platform_account::ManagedPlatformAccount;
pub use managed_account::platform_address::PlatformP2PKHAddress;
pub use mnemonic::Mnemonic;
pub use seed::Seed;
pub use utxo::{Utxo, UtxoSet};
pub use utxo::Utxo;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for any remaining references to UtxoSet in the codebase

echo "=== Searching for UtxoSet references in Rust files ==="
rg -n 'UtxoSet' --type rust

echo -e "\n=== Searching in markdown/docs ==="
rg -n 'UtxoSet' --type md || echo "No markdown references found"

echo -e "\n=== Checking for any other file types mentioning UtxoSet ==="
rg -n 'UtxoSet' --glob '*.toml' --glob '*.txt' || echo "No toml/txt references found"

Repository: dashpay/rust-dashcore

Length of output: 388


🏁 Script executed:

#!/bin/bash
# Check the README content to see how UtxoSet is used in the documentation
echo "=== Checking key-wallet-manager/README.md around lines 154-157 ==="
sed -n '150,160p' key-wallet-manager/README.md

echo -e "\n=== Checking if UtxoSet is exported from key-wallet-manager lib.rs ==="
if [ -f "key-wallet-manager/src/lib.rs" ]; then
  rg -n 'UtxoSet' key-wallet-manager/src/lib.rs || echo "No UtxoSet exports in key-wallet-manager/lib.rs"
fi

echo -e "\n=== Checking key-wallet/src/utxo.rs to see if UtxoSet definition still exists ==="
if [ -f "key-wallet/src/utxo.rs" ]; then
  rg -n 'pub struct UtxoSet' key-wallet/src/utxo.rs -A 3
fi

Repository: dashpay/rust-dashcore

Length of output: 539


🏁 Script executed:

#!/bin/bash
# Check the full key-wallet/src/utxo.rs file
echo "=== Checking key-wallet/src/utxo.rs ==="
wc -l key-wallet/src/utxo.rs

# Search for UtxoSet anywhere in the file
echo -e "\n=== Searching for UtxoSet ==="
cat key-wallet/src/utxo.rs | grep -n -i 'utxoset'

# Show the file structure with pub struct/enum definitions
echo -e "\n=== Public definitions in utxo.rs ==="
rg 'pub (struct|enum|type)' key-wallet/src/utxo.rs

Repository: dashpay/rust-dashcore

Length of output: 219


Breaking API change: UtxoSet removed from public exports and entire codebase.

UtxoSet has been completely removed from the crate. However, the example code in key-wallet-manager/README.md (lines 154–157) still imports and uses UtxoSet, which will no longer work. Update the documentation to remove or replace this example with code that only uses Utxo.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet/src/lib.rs` at line 72, The public API removed UtxoSet but the
README example still imports and uses it; update the example to stop referencing
UtxoSet and show usage with Utxo only. Edit the README example that currently
does `use ...::UtxoSet` and replace the snippet with code that
constructs/iterates/manipulates Utxo instances (e.g., creating Utxo values,
collecting them into a Vec or other local container, and using the existing Utxo
APIs) so documentation compiles against the current public export `Utxo`.

pub use wallet::{balance::WalletCoreBalance, Wallet};

/// Re-export commonly used types
Expand Down
223 changes: 0 additions & 223 deletions key-wallet/src/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
//! This module provides UTXO tracking and management functionality
//! that works with dashcore transaction types.

use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::cmp::Ordering;

use crate::Address;
Expand Down Expand Up @@ -119,200 +117,6 @@ impl PartialOrd for Utxo {
}
}

/// UTXO set management
#[derive(Debug, Clone)]
pub struct UtxoSet {
/// UTXOs indexed by outpoint
utxos: BTreeMap<OutPoint, Utxo>,
/// Total balance
total_balance: u64,
/// Confirmed balance
confirmed_balance: u64,
/// Unconfirmed balance
unconfirmed_balance: u64,
/// Locked balance
locked_balance: u64,
}

impl UtxoSet {
/// Create a new empty UTXO set
pub fn new() -> Self {
Self {
utxos: BTreeMap::new(),
total_balance: 0,
confirmed_balance: 0,
unconfirmed_balance: 0,
locked_balance: 0,
}
}

/// Add a UTXO to the set
pub fn add(&mut self, utxo: Utxo) {
let value = utxo.value();

// Update balances
self.total_balance += value;

if utxo.is_confirmed || utxo.is_instantlocked {
self.confirmed_balance += value;
} else {
self.unconfirmed_balance += value;
}

if utxo.is_locked {
self.locked_balance += value;
}

self.utxos.insert(utxo.outpoint, utxo);
}

/// Remove a UTXO from the set
pub fn remove(&mut self, outpoint: &OutPoint) -> Option<Utxo> {
if let Some(utxo) = self.utxos.remove(outpoint) {
let value = utxo.value();

// Update balances
self.total_balance = self.total_balance.saturating_sub(value);

if utxo.is_confirmed || utxo.is_instantlocked {
self.confirmed_balance = self.confirmed_balance.saturating_sub(value);
} else {
self.unconfirmed_balance = self.unconfirmed_balance.saturating_sub(value);
}

if utxo.is_locked {
self.locked_balance = self.locked_balance.saturating_sub(value);
}

Some(utxo)
} else {
None
}
}

/// Get a UTXO by outpoint
pub fn get(&self, outpoint: &OutPoint) -> Option<&Utxo> {
self.utxos.get(outpoint)
}

/// Get a mutable UTXO by outpoint
pub fn get_mut(&mut self, outpoint: &OutPoint) -> Option<&mut Utxo> {
self.utxos.get_mut(outpoint)
}

/// Check if a UTXO exists
pub fn contains(&self, outpoint: &OutPoint) -> bool {
self.utxos.contains_key(outpoint)
}

/// Get all UTXOs
pub fn all(&self) -> Vec<&Utxo> {
self.utxos.values().collect()
}

/// Get all spendable UTXOs
pub fn spendable(&self, current_height: u32) -> Vec<&Utxo> {
self.utxos.values().filter(|utxo| utxo.is_spendable(current_height)).collect()
}

/// Get all UTXOs for a specific address
pub fn for_address(&self, address: &Address) -> Vec<&Utxo> {
self.utxos.values().filter(|utxo| &utxo.address == address).collect()
}

/// Get total balance
pub fn total_balance(&self) -> u64 {
self.total_balance
}

/// Get confirmed balance
pub fn confirmed_balance(&self) -> u64 {
self.confirmed_balance
}

/// Get unconfirmed balance
pub fn unconfirmed_balance(&self) -> u64 {
self.unconfirmed_balance
}

/// Get locked balance
pub fn locked_balance(&self) -> u64 {
self.locked_balance
}

/// Get spendable balance
pub fn spendable_balance(&self, current_height: u32) -> u64 {
self.spendable(current_height).iter().map(|utxo| utxo.value()).sum()
}

/// Clear all UTXOs
pub fn clear(&mut self) {
self.utxos.clear();
self.total_balance = 0;
self.confirmed_balance = 0;
self.unconfirmed_balance = 0;
self.locked_balance = 0;
}

/// Get the number of UTXOs
pub fn len(&self) -> usize {
self.utxos.len()
}

/// Check if the set is empty
pub fn is_empty(&self) -> bool {
self.utxos.is_empty()
}

/// Update confirmation status for a UTXO
pub fn update_confirmation(&mut self, outpoint: &OutPoint, confirmed: bool) {
if let Some(utxo) = self.utxos.get_mut(outpoint) {
let value = utxo.value();

if utxo.is_confirmed != confirmed {
if confirmed {
self.confirmed_balance += value;
self.unconfirmed_balance = self.unconfirmed_balance.saturating_sub(value);
} else {
self.unconfirmed_balance += value;
self.confirmed_balance = self.confirmed_balance.saturating_sub(value);
}
utxo.is_confirmed = confirmed;
}
}
}

/// Lock a UTXO
pub fn lock_utxo(&mut self, outpoint: &OutPoint) -> bool {
if let Some(utxo) = self.utxos.get_mut(outpoint) {
if !utxo.is_locked {
utxo.lock();
self.locked_balance += utxo.value();
return true;
}
}
false
}

/// Unlock a UTXO
pub fn unlock_utxo(&mut self, outpoint: &OutPoint) -> bool {
if let Some(utxo) = self.utxos.get_mut(outpoint) {
if utxo.is_locked {
utxo.unlock();
self.locked_balance = self.locked_balance.saturating_sub(utxo.value());
return true;
}
}
false
}
}

impl Default for UtxoSet {
fn default() -> Self {
Self::new()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -334,33 +138,6 @@ mod tests {
assert!(!utxo.is_spendable(200));
}

#[test]
fn test_utxo_set_operations() {
let mut set = UtxoSet::new();

let utxo1 = Utxo::dummy(0, 100000, 100, false, false);
let utxo2 = Utxo::dummy(1, 200000, 150, false, false);

set.add(utxo1.clone());
set.add(utxo2.clone());

assert_eq!(set.len(), 2);
assert_eq!(set.total_balance(), 300000);
assert_eq!(set.unconfirmed_balance(), 300000);
assert_eq!(set.confirmed_balance(), 0);

// Update confirmation
set.update_confirmation(&utxo1.outpoint, true);
assert_eq!(set.confirmed_balance(), 100000);
assert_eq!(set.unconfirmed_balance(), 200000);

// Remove UTXO
let removed = set.remove(&utxo1.outpoint);
assert!(removed.is_some());
assert_eq!(set.len(), 1);
assert_eq!(set.total_balance(), 200000);
}

#[test_case(false, 0, 500, 0 ; "unconfirmed utxo has 0 confirmations")]
#[test_case(true, 0, 500, 501 ; "confirmed utxo at genesis height has 501 confirmations")]
#[test_case(true, 1000, 500, 0 ; "utxo height greater than current height has 0 confirmations")]
Expand Down
Loading