1use bitcoin::{Transaction, Txid, TxOut, Block};
2use bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR;
3
4use crate::*;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct TxDBKey {
8 txid: Txid,
9}
10
11impl Serialize for TxDBKey {
12 fn serialize(&self) -> Vec<u8> {
13 consensus_encode(&self.txid)
14 }
15}
16
17impl Deserialize for TxDBKey {
18 fn deserialize(buf: &[u8]) -> Self {
19 Self {
20 txid: consensus_decode(buf)
21 }
22 }
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct TxDBValue {
27 pub confirmed_height: Option<u32>,
28 pub tx: Transaction,
29 pub previous_txouts: Vec<TxOut>,
30}
31
32impl TxDBValue {
33 pub fn deserialize_as_rawtx(buf: &[u8]) -> (Option<u32>, Vec<u8>, Vec<TxOut>) {
34 let confirmed_height = bytes_to_i32(&buf[0..4]);
35 let confirmed_height = if confirmed_height >= 0 {
36 Some(confirmed_height as u32)
37 } else {
38 None
39 };
40 let tx_len = bytes_to_u32(&buf[4..8]) as usize;
41 let tx = buf[8..tx_len+8].to_vec();
42 let mut offset: usize = tx_len + 8;
43 let mut previous_txouts = Vec::new();
44 while offset < buf.len() {
45 let txout_len = bytes_to_u32(&buf[offset..offset+4]) as usize;
46 offset += 4;
47 let txout = consensus_decode(&buf[offset..txout_len+offset]);
48 offset += txout_len;
49 previous_txouts.push(txout);
50 }
51 (confirmed_height, tx, previous_txouts)
52 }
53}
54
55impl Serialize for TxDBValue {
56 fn serialize(&self) -> Vec<u8> {
57 let mut ret = Vec::new();
58 let confirmed_height = self.confirmed_height.map_or_else(|| -1i32, |confirmed_height| confirmed_height as i32);
59 ret.push(confirmed_height.to_le_bytes().to_vec());
60 let tx = consensus_encode(&self.tx);
61 let tx_len = tx.len() as u32;
62 ret.push(tx_len.to_le_bytes().to_vec());
63 ret.push(tx);
64 for txout in self.previous_txouts.iter() {
65 let txout = consensus_encode(txout);
66 let txout_len = txout.len() as u32;
67 ret.push(txout_len.to_le_bytes().to_vec());
68 ret.push(txout);
69 }
70 ret.concat()
71 }
72}
73
74impl Deserialize for TxDBValue {
75 fn deserialize(buf: &[u8]) -> Self {
76 let (confirmed_height, tx, previous_txouts) = Self::deserialize_as_rawtx(buf);
77 Self {
78 confirmed_height,
79 tx: consensus_decode(&tx),
80 previous_txouts,
81 }
82 }
83}
84
85#[derive(Debug)]
86pub struct TxDB {
87 db: RocksDB<TxDBKey, TxDBValue>,
88}
89
90impl TxDB {
91 pub fn path(coin: &str) -> String {
92 format!("{}/{}/tx", data_dir(), coin)
93 }
94 pub fn new(coin: &str, temporary: bool) -> Self {
95 let path = Self::path(coin);
96 Self {
97 db: RocksDB::new(&path, temporary),
98 }
99 }
100 pub fn put(&self, txid: &Txid, value: &TxDBValue) {
101 self.db.put(&TxDBKey { txid: *txid }, value);
102 }
103 pub fn put_tx(&self, tx: &Transaction, confirmed_height: Option<u32>) -> Result<TxDBValue, Txid> {
104 let mut previous_txouts = Vec::new();
105 for vin in tx.input.iter() {
106 if !vin.previous_output.is_null() {
107 let previous_txid = &vin.previous_output.txid;
108 match self.get(previous_txid) {
109 Some(previous_tx) => previous_txouts.push(previous_tx.tx.output[vin.previous_output.vout as usize].clone()),
110 None => return Err(*previous_txid),
111 }
112 }
113 }
114 let value = TxDBValue {
115 confirmed_height,
116 tx: (*tx).clone(),
117 previous_txouts,
118 };
119 self.put(&tx.txid(), &value);
120 Ok(value)
121 }
122 pub fn get(&self, txid: &Txid) -> Option<TxDBValue> {
123 self.db.get(&TxDBKey { txid: *txid })
124 }
125 pub fn get_as_rest(&self, txid: &Txid, config: &Config) -> Option<RestTx> {
126 let buf = self.db.get_raw(&TxDBKey { txid: *txid });
128 buf.map_or_else(|| None, |buf| {
130 let (confirmed_height, rawtx, previous_txouts) = TxDBValue::deserialize_as_rawtx(&buf);
132 let tx: Transaction = consensus_decode(&rawtx);
133 let mut input_value = 0;
134 let mut vin = Vec::new();
135 let mut previous_txout_index = 0;
136 for input in tx.input.iter() {
137 if input.previous_output.is_null() {
138 vin.push(RestVin::new(input, &None, config));
139 } else {
140 input_value += previous_txouts[previous_txout_index].value;
141 vin.push(RestVin::new(input, &Some(previous_txouts[previous_txout_index].clone()), config));
142 previous_txout_index += 1;
143 }
144 }
145 let output_value: u64 = tx.output.iter().map(|output| output.value).sum();
146 let tx = RestTx {
147 confirmed_height,
148 hex: hex::encode(&rawtx),
149 txid: tx.txid().to_string(),
150 hash: tx.wtxid().to_string(),
151 size: tx.get_size(),
152 vsize: (tx.get_weight() + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR,
155 weight: tx.get_weight(),
156 version: tx.version,
157 locktime: tx.lock_time,
158 vin,
159 vout: tx.output.iter().enumerate().map(|(n, vout)| RestVout::new(vout, n, config)).collect(),
160 fee: (input_value as i64) - (output_value as i64),
162 };
163 Some(tx)
165 })
166 }
167 pub fn multi_get<I: IntoIterator<Item = Txid>>(&self, txids: I) -> Vec<Option<TxDBValue>> {
168 let txids: Vec<TxDBKey> = txids.into_iter().map(|txid| TxDBKey { txid }).collect();
169 self.db.multi_get(txids)
170 }
171 pub fn process_block(&self, confirmed_height: u32, block: &Block, previous_utxos: &[UtxoEntry]) {
172 let mut previous_utxo_index = 0;
173 for tx in block.txdata.iter() {
174 let mut previous_txouts = Vec::new();
176 for vin in tx.input.iter() {
177 if !vin.previous_output.is_null() {
178 let txout = TxOut {
179 value: previous_utxos[previous_utxo_index].value,
180 script_pubkey: previous_utxos[previous_utxo_index].script_pubkey.clone(),
181 };
182 previous_txouts.push(txout);
183 previous_utxo_index += 1;
184 }
185 }
186 let value = TxDBValue {
187 confirmed_height: Some(confirmed_height),
188 tx: (*tx).clone(),
189 previous_txouts,
190 };
191 self.put(&tx.txid(), &value);
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use std::str::FromStr;
199 use super::*;
200 const TXID: &str = "503e4e9824282eb06f1a328484e2b367b5f4f93a405d6e7b97261bafabfb53d5";
201 #[test]
202 fn key_deserialize() {
203 assert_eq!(
204 TxDBKey {
205 txid: Txid::from_str(TXID).unwrap(),
206 },
207 TxDBKey::deserialize(&Txid::from_hex(TXID).unwrap()),
208 );
209 }
210 #[test]
211 fn put_unconfirmed() {
212 let tx = &fixtures::regtest_blocks()[0].txdata[0];
213 let tx_db = TxDB::new("test/tx/unconfirmed", true);
214 tx_db.put_tx(&tx, None).unwrap();
215 assert_eq!(
216 tx_db.get(&tx.txid()).unwrap(),
217 TxDBValue {
218 confirmed_height: None,
219 tx: (*tx).clone(),
220 previous_txouts: Vec::new(),
221 },
222 );
223 }
224 #[test]
225 fn put_confirmed() {
226 let blocks = fixtures::regtest_blocks();
227 let mut utxo_db = UtxoDB::new("test/tx/confirmed", true);
228 let tx_db = TxDB::new("test/tx/confirmed", true);
229 let mut previous_utxos_vec = Vec::new();
230 for (height, block) in blocks.iter().enumerate() {
231 let previous_utxos = utxo_db.process_block(&block, true);
232 tx_db.process_block(height as u32, &block, &previous_utxos);
233 previous_utxos_vec.push(previous_utxos);
234 }
235 assert_eq!(
237 tx_db.put_tx(&consensus_decode(&hex::decode("01000000000101d553fbabaf1b26977b6e5d403af9f4b567b3e28484321a6fb02e2824984e3e5000000000171600142b2296c588ec413cebd19c3cbc04ea830ead6e78ffffffff01be1611020000000017a91487e4e5a7ff7bf78b8a8972a49381c8a673917f3e870247304402205f39ccbab38b644acea0776d18cb63ce3e37428cbac06dc23b59c61607aef69102206b8610827e9cb853ea0ba38983662034bd3575cc1ab118fb66d6a98066fa0bed01210304c01563d46e38264283b99bb352b46e69bf132431f102d4bd9a9d8dab075e7f00000000").unwrap()), Some(500_000)),
238 Result::<TxDBValue, Txid>::Err(Txid::from_str(TXID).unwrap()),
239 );
240 for (height, block) in blocks.iter().enumerate() {
241 let mut previous_utxo_index = 0;
242 for tx in block.txdata.iter() {
243 let mut previous_txout_index = 0;
244 let value = tx_db.get(&tx.txid()).unwrap();
245 assert_eq!(value.confirmed_height, Some(height as u32));
246 assert_eq!(value.tx, *tx);
247 for vin in tx.input.iter() {
248 if !vin.previous_output.is_null() {
249 let txout = TxOut {
250 value: previous_utxos_vec[height][previous_utxo_index].value,
251 script_pubkey: previous_utxos_vec[height][previous_utxo_index].script_pubkey.clone(),
252 };
253 assert_eq!(value.previous_txouts[previous_txout_index], txout);
254 previous_utxo_index += 1;
255 previous_txout_index += 1;
256 }
257 }
258 }
259 }
260 }
261}