1use std::collections::BTreeMap;
18
19use bitcoin::{Transaction, TxIn, TxOut};
20use wallet::psbt::{self, Psbt, PsbtVersion};
21
22use crate::channel::Funding;
23
24pub trait TxRole: Clone + From<u16> + Into<u16> {}
25pub trait TxIndex: Clone + From<u64> + Into<u64> {}
26
27impl TxRole for u16 {}
28impl TxIndex for u64 {}
29
30#[derive(Getters, Clone, Eq, PartialEq)]
31pub struct TxGraph<'channel> {
32 funding: &'channel Funding,
34 pub cmt_version: i32,
35 pub cmt_locktime: u32,
36 pub cmt_sequence: u32,
37 pub cmt_outs: Vec<psbt::Output>,
38 graph: BTreeMap<u16, BTreeMap<u64, Psbt>>,
39}
40
41impl<'channel> TxGraph<'channel>
42where
43 Self: 'channel,
44{
45 pub fn from_funding(funding: &'channel Funding) -> TxGraph<'channel> {
46 TxGraph {
47 funding,
48 cmt_version: 0,
50 cmt_locktime: 0,
51 cmt_sequence: 0,
52 cmt_outs: vec![],
53 graph: bmap! {},
54 }
55 }
56
57 pub fn tx<R, I>(&self, role: R, index: I) -> Option<&Psbt>
58 where
59 R: TxRole,
60 I: TxIndex,
61 {
62 self.graph
63 .get(&role.into())
64 .and_then(|v| v.get(&index.into()))
65 }
66
67 pub fn tx_mut<R, I>(&mut self, role: R, index: I) -> Option<&mut Psbt>
68 where
69 R: TxRole,
70 I: TxIndex,
71 {
72 self.graph
73 .get_mut(&role.into())
74 .and_then(|v| v.get_mut(&index.into()))
75 }
76
77 pub fn insert_tx<R, I>(
78 &mut self,
79 role: R,
80 index: I,
81 psbt: Psbt,
82 ) -> Option<Psbt>
83 where
84 R: TxRole,
85 I: TxIndex,
86 {
87 self.graph
88 .entry(role.into())
89 .or_insert_with(Default::default)
90 .insert(index.into(), psbt)
91 }
92
93 pub fn len(&self) -> usize {
94 self.graph
95 .iter()
96 .fold(0usize, |sum, (_, map)| sum + map.len())
97 }
98
99 pub fn is_empty(&self) -> bool {
100 self.graph.len() == 0
101 }
102
103 pub fn last_index<R>(&self, role: R) -> usize
104 where
105 R: TxRole,
106 {
107 match self.graph.get(&role.into()) {
108 Some(map) => map.len(),
109 None => 0usize,
110 }
111 }
112
113 pub fn render(&self) -> Vec<Psbt> {
114 let mut txes = Vec::with_capacity(self.len());
115 let cmt_tx = self.render_cmt();
116 txes.push(cmt_tx);
117 txes.extend(self.graph.values().flat_map(|v| v.values().cloned()));
118 txes
119 }
120
121 pub fn render_cmt(&self) -> Psbt {
122 let cmt_tx = Transaction {
123 version: self.cmt_version,
124 lock_time: bitcoin::PackedLockTime(self.cmt_locktime),
125 input: vec![TxIn {
126 previous_output: self.funding.outpoint(),
127 script_sig: empty!(),
128 sequence: bitcoin::Sequence(self.cmt_sequence),
129 witness: empty!(),
130 }],
131 output: vec![default!(); self.cmt_outs.len()],
132 };
133 let mut psbt = Psbt::with(cmt_tx, PsbtVersion::V0).expect(
134 "PSBT construction fails only if script_sig and witness are not \
135 empty; which is not the case here",
136 );
137 let funding_psbt = self.funding.psbt();
138 let funding_vout = self.funding.output() as usize;
139 let funding_output = &funding_psbt.outputs[funding_vout];
140 psbt.inputs[0].witness_utxo = Some(TxOut {
141 value: funding_output.amount,
142 script_pubkey: funding_output.script.clone().into(),
143 });
144 psbt.inputs[0].witness_script = funding_output.witness_script.clone();
145 psbt.inputs[0].bip32_derivation =
146 funding_output.bip32_derivation.clone();
147 for (index, output) in psbt.outputs.iter_mut().enumerate() {
148 *output = self.cmt_outs[index].clone();
149 }
150 psbt
151 }
152
153 pub fn iter(&self) -> GraphIter {
154 GraphIter::with(self)
155 }
156
157 pub fn vec_mut(&mut self) -> Vec<(u16, u64, &mut Psbt)> {
158 let vec = self
159 .graph
160 .iter_mut()
161 .flat_map(|(role, map)| {
162 map.iter_mut().map(move |(index, tx)| (*role, *index, tx))
163 })
164 .collect::<Vec<_>>();
165 vec
166 }
167}
168
169pub struct GraphIter<'iter, 'channel> {
170 graph: &'iter TxGraph<'channel>,
171 curr_role: u16,
172 curr_index: u64,
173}
174
175impl<'iter, 'channel> GraphIter<'iter, 'channel> {
176 fn with(graph: &'iter TxGraph<'channel>) -> Self {
177 Self {
178 graph,
179 curr_role: 0,
180 curr_index: 0,
181 }
182 }
183}
184
185impl<'iter, 'channel> Iterator for GraphIter<'iter, 'channel> {
186 type Item = (u16, u64, &'iter Psbt);
187
188 fn next(&mut self) -> Option<Self::Item> {
189 let tx = self.graph.tx(self.curr_role, self.curr_index).or_else(|| {
190 self.curr_role += 1;
191 self.curr_index = 0;
192 self.graph.tx(self.curr_role, self.curr_index)
193 });
194 self.curr_index += 1;
195 tx.map(|tx| (self.curr_role, self.curr_index, tx))
196 }
197}