1pub use bitcoin::consensus::{deserialize, serialize};
2pub use bitcoin::hex::FromHex;
3use bitcoin::Weight;
4pub use bitcoin::{
5 transaction, Amount, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, Witness,
6};
7
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10
11#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
13pub struct WaterfallResponse {
14 pub txs_seen: BTreeMap<String, Vec<Vec<TxSeen>>>,
15 pub page: u16,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub tip: Option<BlockHash>,
18
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub tip_meta: Option<BlockMeta>,
21}
22
23#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Ord, PartialOrd)]
24pub struct BlockMeta {
25 pub b: BlockHash,
27
28 pub t: u32,
30
31 pub h: u32,
33}
34
35#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
37pub struct TxSeen {
38 pub txid: Txid,
39 pub height: u32,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub block_hash: Option<BlockHash>,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub block_timestamp: Option<u32>,
44 #[serde(skip_serializing_if = "V::is_undefined", default)]
45 pub v: V,
46}
47
48#[derive(Clone, PartialEq, Eq, Debug, Default)]
50pub enum V {
51 #[default]
52 Undefined,
53 Vin(u32),
54 Vout(u32),
55}
56
57impl V {
58 pub fn is_undefined(&self) -> bool {
59 matches!(self, V::Undefined)
60 }
61
62 pub fn raw(&self) -> i32 {
63 match self {
64 V::Undefined => 0,
65 V::Vout(n) => *n as i32,
66 V::Vin(n) => -(*n as i32) - 1,
67 }
68 }
69
70 pub fn from_raw(raw: i32) -> Self {
71 match raw {
72 0 => V::Undefined,
73 x if x > 0 => V::Vout(x as u32),
74 x => V::Vin((-x - 1) as u32),
75 }
76 }
77}
78
79impl Serialize for V {
80 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: serde::Serializer,
83 {
84 serializer.serialize_i32(self.raw())
85 }
86}
87
88impl<'de> Deserialize<'de> for V {
89 fn deserialize<D>(deserializer: D) -> Result<V, D::Error>
90 where
91 D: serde::Deserializer<'de>,
92 {
93 let raw = i32::deserialize(deserializer)?;
94 Ok(V::from_raw(raw))
95 }
96}
97
98impl WaterfallResponse {
99 pub fn is_empty(&self) -> bool {
100 self.txs_seen
101 .iter()
102 .flat_map(|(_, v)| v.iter())
103 .all(|a| a.is_empty())
104 }
105}
106
107#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
108pub struct PrevOut {
109 pub value: u64,
110 pub scriptpubkey: ScriptBuf,
111}
112
113#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
114pub struct Vin {
115 pub txid: Txid,
116 pub vout: u32,
117 pub prevout: Option<PrevOut>,
119 pub scriptsig: ScriptBuf,
120 #[serde(deserialize_with = "deserialize_witness", default)]
121 pub witness: Vec<Vec<u8>>,
122 pub sequence: u32,
123 pub is_coinbase: bool,
124}
125
126#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
127pub struct Vout {
128 pub value: u64,
129 pub scriptpubkey: ScriptBuf,
130}
131
132#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
133pub struct TxStatus {
134 pub confirmed: bool,
135 pub block_height: Option<u32>,
136 pub block_hash: Option<BlockHash>,
137 pub block_time: Option<u64>,
138}
139
140#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
141pub struct MerkleProof {
142 pub block_height: u32,
143 pub merkle: Vec<Txid>,
144 pub pos: usize,
145}
146
147#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
148pub struct OutputStatus {
149 pub spent: bool,
150 pub txid: Option<Txid>,
151 pub vin: Option<u64>,
152 pub status: Option<TxStatus>,
153}
154
155#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
156pub struct BlockStatus {
157 pub in_best_chain: bool,
158 pub height: Option<u32>,
159 pub next_best: Option<BlockHash>,
160}
161
162#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
163pub struct Tx {
164 pub txid: Txid,
165 pub version: i32,
166 pub locktime: u32,
167 pub vin: Vec<Vin>,
168 pub vout: Vec<Vout>,
169 pub size: usize,
171 pub weight: u64,
173 pub status: TxStatus,
174 pub fee: u64,
175}
176
177#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
178pub struct BlockTime {
179 pub timestamp: u64,
180 pub height: u32,
181}
182
183#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
184pub struct BlockSummary {
185 pub id: BlockHash,
186 #[serde(flatten)]
187 pub time: BlockTime,
188 pub previousblockhash: Option<bitcoin::BlockHash>,
190 pub merkle_root: bitcoin::hash_types::TxMerkleNode,
191}
192
193#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
195pub struct AddressStats {
196 pub address: String,
198 pub chain_stats: AddressTxsSummary,
200 pub mempool_stats: AddressTxsSummary,
202}
203
204#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
206pub struct AddressTxsSummary {
207 pub funded_txo_count: u32,
209 pub funded_txo_sum: u64,
211 pub spent_txo_count: u32,
213 pub spent_txo_sum: u64,
215 pub tx_count: u32,
217}
218
219impl Tx {
220 pub fn to_tx(&self) -> Transaction {
221 Transaction {
222 version: transaction::Version::non_standard(self.version),
223 lock_time: bitcoin::absolute::LockTime::from_consensus(self.locktime),
224 input: self
225 .vin
226 .iter()
227 .cloned()
228 .map(|vin| TxIn {
229 previous_output: OutPoint {
230 txid: vin.txid,
231 vout: vin.vout,
232 },
233 script_sig: vin.scriptsig,
234 sequence: bitcoin::Sequence(vin.sequence),
235 witness: Witness::from_slice(&vin.witness),
236 })
237 .collect(),
238 output: self
239 .vout
240 .iter()
241 .cloned()
242 .map(|vout| TxOut {
243 value: Amount::from_sat(vout.value),
244 script_pubkey: vout.scriptpubkey,
245 })
246 .collect(),
247 }
248 }
249
250 pub fn confirmation_time(&self) -> Option<BlockTime> {
251 match self.status {
252 TxStatus {
253 confirmed: true,
254 block_height: Some(height),
255 block_time: Some(timestamp),
256 ..
257 } => Some(BlockTime { timestamp, height }),
258 _ => None,
259 }
260 }
261
262 pub fn previous_outputs(&self) -> Vec<Option<TxOut>> {
263 self.vin
264 .iter()
265 .cloned()
266 .map(|vin| {
267 vin.prevout.map(|po| TxOut {
268 script_pubkey: po.scriptpubkey,
269 value: Amount::from_sat(po.value),
270 })
271 })
272 .collect()
273 }
274
275 pub fn weight(&self) -> Weight {
276 Weight::from_wu(self.weight)
277 }
278
279 pub fn fee(&self) -> Amount {
280 Amount::from_sat(self.fee)
281 }
282}
283
284fn deserialize_witness<'de, D>(d: D) -> Result<Vec<Vec<u8>>, D::Error>
285where
286 D: serde::de::Deserializer<'de>,
287{
288 let list = Vec::<String>::deserialize(d)?;
289 list.into_iter()
290 .map(|hex_str| Vec::<u8>::from_hex(&hex_str))
291 .collect::<Result<Vec<Vec<u8>>, _>>()
292 .map_err(serde::de::Error::custom)
293}