Skip to content
Closed
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
4 changes: 4 additions & 0 deletions dash-spv/src/client/block_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ impl<W: WalletInterface + Send + Sync + 'static, S: StorageManager + Send + Sync
// Process block with wallet
let mut wallet = self.wallet.write().await;
let txids = wallet.process_block(&block, height, self.network).await;

// Update chain height to process any matured coinbase transactions
wallet.update_chain_height(self.network, height).await;

if !txids.is_empty() {
tracing::info!(
"🎯 Wallet found {} relevant transactions in block {} at height {}",
Expand Down
4 changes: 4 additions & 0 deletions dash-spv/src/client/block_processor_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ mod tests {
let map = self.effects.lock().await;
map.get(&tx.txid()).cloned()
}

async fn update_chain_height(&mut self, _network: Network, _height: u32) {}
}

fn create_test_block(network: Network) -> Block {
Expand Down Expand Up @@ -299,6 +301,8 @@ mod tests {
async fn describe(&self, _network: Network) -> String {
"NonMatchingWallet (test implementation)".to_string()
}

async fn update_chain_height(&mut self, _network: Network, _height: u32) {}
}

let (task_tx, task_rx) = mpsc::unbounded_channel();
Expand Down
3 changes: 3 additions & 0 deletions dash-spv/src/sync/sequential/message_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,9 @@ impl<

let relevant_txids = wallet.process_block(&block, block_height, self.config.network).await;

// Update chain height to process any matured coinbase transactions
wallet.update_chain_height(self.config.network, block_height).await;

drop(wallet);

if !relevant_txids.is_empty() {
Expand Down
6 changes: 6 additions & 0 deletions key-wallet-manager/src/wallet_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,10 @@ pub trait WalletInterface: Send + Sync {
async fn describe(&self, _network: Network) -> String {
"Wallet interface description unavailable".to_string()
}

/// Notify the wallet that the chain has advanced to a new height.
///
/// This processes any coinbase transactions that have matured (reached 100 confirmations)
/// and adds their UTXOs to the spendable balance.
async fn update_chain_height(&mut self, network: Network, height: CoreBlockHeight);
}
6 changes: 6 additions & 0 deletions key-wallet-manager/src/wallet_manager/process_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,10 @@ impl<T: WalletInfoInterface + Send + Sync + 'static> WalletInterface for WalletM

format!("WalletManager: {} wallet(s) on {}\n{}", wallet_count, network, details.join("\n"))
}

async fn update_chain_height(&mut self, network: Network, height: CoreBlockHeight) {
for info in self.wallet_infos.values_mut() {
info.update_chain_height(network, height);
}
}
}
15 changes: 14 additions & 1 deletion key-wallet/src/managed_account/managed_account_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::wallet::balance::WalletBalance;
use crate::Network;
use alloc::collections::BTreeMap;
use dashcore::blockdata::transaction::OutPoint;
use dashcore::Txid;
use dashcore::{Address, Txid};

/// Common trait for all managed account types
pub trait ManagedAccountTrait {
Expand Down Expand Up @@ -44,6 +44,19 @@ pub trait ManagedAccountTrait {
/// Get mutable transactions
fn transactions_mut(&mut self) -> &mut BTreeMap<Txid, TransactionRecord>;

/// Extract UTXOs from a transaction and add them to this account.
///
/// Scans the transaction outputs for addresses belonging to `involved_addresses`
/// and creates UTXOs for any matches.
fn add_utxos_from_transaction(
&mut self,
tx: &dashcore::Transaction,
involved_addresses: &alloc::collections::BTreeSet<Address>,
network: Network,
height: u32,
is_confirmed: bool,
);

/// Get UTXOs
fn utxos(&self) -> &BTreeMap<OutPoint, Utxo>;

Expand Down
34 changes: 34 additions & 0 deletions key-wallet/src/managed_account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,40 @@ impl ManagedAccountTrait for ManagedAccount {
&mut self.transactions
}

fn add_utxos_from_transaction(
&mut self,
tx: &dashcore::Transaction,
involved_addresses: &alloc::collections::BTreeSet<Address>,
network: Network,
height: u32,
is_confirmed: bool,
) {
let txid = tx.txid();
for (vout, output) in tx.output.iter().enumerate() {
if let Ok(addr) = Address::from_script(&output.script_pubkey, network) {
if involved_addresses.contains(&addr) {
let outpoint = OutPoint {
txid,
vout: vout as u32,
};
let txout = dashcore::TxOut {
value: output.value,
script_pubkey: output.script_pubkey.clone(),
};
let mut utxo = Utxo::new(outpoint, txout, addr, height, tx.is_coin_base());
utxo.is_confirmed = is_confirmed;
tracing::debug!(
"Adding UTXO {}:{} value={} to account",
txid,
vout,
output.value
);
self.utxos.insert(outpoint, utxo);
}
}
}
}

fn utxos(&self) -> &BTreeMap<OutPoint, Utxo> {
&self.utxos
}
Expand Down
33 changes: 9 additions & 24 deletions key-wallet/src/transaction_checking/wallet_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

pub(crate) use super::account_checker::TransactionCheckResult;
use super::transaction_router::TransactionRouter;
use crate::managed_account::managed_account_trait::ManagedAccountTrait;
use crate::wallet::immature_transaction::ImmatureTransaction;
use crate::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface;
use crate::wallet::managed_wallet_info::ManagedWalletInfo;
use crate::{Network, Utxo, Wallet};
use crate::{Network, Wallet};
use async_trait::async_trait;
use dashcore::blockdata::transaction::Transaction;
use dashcore::BlockHash;
use dashcore::{Address as DashAddress, OutPoint};
use dashcore_hashes::Hash;

/// Context for transaction processing
Expand Down Expand Up @@ -205,28 +205,13 @@ impl WalletTransactionChecker for ManagedWalletInfo {

// Insert UTXOs for matching outputs (skip for immature coinbase)
if !needs_maturity {
let txid = tx.txid();
for (vout, output) in tx.output.iter().enumerate() {
if let Ok(addr) = DashAddress::from_script(&output.script_pubkey, network) {
if involved_addrs.contains(&addr) {
let outpoint = OutPoint { txid, vout: vout as u32 };
// Construct TxOut clone explicitly to avoid trait assumptions
let txout = dashcore::TxOut {
value: output.value,
script_pubkey: output.script_pubkey.clone(),
};
let mut utxo = Utxo::new(
outpoint,
txout,
addr,
utxo_height,
tx.is_coin_base(),
);
utxo.is_confirmed = is_confirmed;
account.utxos.insert(outpoint, utxo);
}
}
}
account.add_utxos_from_transaction(
tx,
&involved_addrs,
network,
utxo_height,
is_confirmed,
);
}

// Remove any UTXOs that are being spent by this transaction
Expand Down
35 changes: 35 additions & 0 deletions key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::wallet::managed_wallet_info::TransactionRecord;
use crate::wallet::ManagedWalletInfo;
use crate::{Network, Utxo, Wallet, WalletBalance};
use dashcore::{Address as DashAddress, Address, Transaction};

use crate::account::ManagedAccountTrait;
use std::collections::BTreeSet;

/// Trait that wallet info types must implement to work with WalletManager
Expand Down Expand Up @@ -272,6 +274,17 @@ impl WalletInfoInterface for ManagedWalletInfo {
false, // Not ours (we received)
);
account.transactions.insert(tx.txid, tx_record);

// Add UTXOs for outputs that belong to this account
let account_addresses: BTreeSet<Address> =
account.all_addresses().into_iter().collect();
account.add_utxos_from_transaction(
&tx.transaction,
&account_addresses,
network,
tx.height,
true,
);
}
}

Expand All @@ -289,6 +302,17 @@ impl WalletInfoInterface for ManagedWalletInfo {
false,
);
account.transactions.insert(tx.txid, tx_record);

// Add UTXOs for outputs that belong to this account
let account_addresses: BTreeSet<Address> =
account.all_addresses().into_iter().collect();
account.add_utxos_from_transaction(
&tx.transaction,
&account_addresses,
network,
tx.height,
true,
);
}
}

Expand All @@ -305,6 +329,17 @@ impl WalletInfoInterface for ManagedWalletInfo {
false,
);
account.transactions.insert(tx.txid, tx_record);

// Add UTXOs for outputs that belong to this account
let account_addresses: BTreeSet<Address> =
account.all_addresses().into_iter().collect();
account.add_utxos_from_transaction(
&tx.transaction,
&account_addresses,
network,
tx.height,
true,
);
}
}
}
Expand Down
Loading