cardano_sdk/wallet/
utxo.rs

1use crate::chain::{TransactionOutput, TxHash, TxIndex};
2use std::collections::{btree_map::Entry, BTreeMap};
3
4pub struct Utxos {
5    inner: BTreeMap<TxHash, ConsumableUtxo>,
6}
7
8pub enum UtxosError {
9    DuplicateTx(TxHash),
10    UsingInexistantTx(TxHash),
11    UsingInexistantTxIndex(TxHash, TxIndex),
12}
13
14impl Utxos {
15    pub fn new() -> Self {
16        Self {
17            inner: BTreeMap::new(),
18        }
19    }
20
21    pub fn add(
22        &mut self,
23        key: TxHash,
24        value: Vec<(TxIndex, TransactionOutput)>,
25    ) -> Result<(), UtxosError> {
26        if self
27            .inner
28            .insert(key.clone(), ConsumableUtxo::new(value))
29            .is_some()
30        {
31            return Err(UtxosError::DuplicateTx(key));
32        }
33        Ok(())
34    }
35
36    pub fn remove(&mut self, key: TxHash, value: TxIndex) -> Result<(), UtxosError> {
37        match self.inner.entry(key.clone()) {
38            Entry::Vacant(_) => {
39                return Err(UtxosError::UsingInexistantTx(key));
40            }
41            Entry::Occupied(mut ent) => match ent.get_mut().consume(value) {
42                Err(()) => return Err(UtxosError::UsingInexistantTxIndex(key, value)),
43                Ok(()) => {
44                    if ent.get().is_empty() {
45                        ent.remove_entry();
46                    }
47                    Ok(())
48                }
49            },
50        }
51    }
52
53    pub fn iter(&self) -> impl Iterator<Item = (&TxHash, &TxIndex, &TransactionOutput)> {
54        self.inner
55            .iter()
56            .map(|(k, v)| v.iter().map(move |(txidx, txo)| (k, txidx, txo)))
57            .flatten()
58    }
59}
60
61pub struct ConsumableUtxo(BTreeMap<TxIndex, TransactionOutput>);
62
63impl ConsumableUtxo {
64    pub fn new(outs: Vec<(TxIndex, TransactionOutput)>) -> Self {
65        let map = outs.into_iter().collect();
66        Self(map)
67    }
68
69    pub fn is_consumable(&self, index: TxIndex) -> bool {
70        self.0.contains_key(&index)
71    }
72
73    pub fn consume(&mut self, index: TxIndex) -> Result<(), ()> {
74        match self.0.remove(&index) {
75            None => Ok(()),
76            Some(_) => Err(()),
77        }
78    }
79
80    pub fn is_empty(&self) -> bool {
81        self.0.is_empty()
82    }
83
84    pub fn iter(&self) -> impl Iterator<Item = (&TxIndex, &TransactionOutput)> {
85        self.0.iter()
86    }
87}