1use elements::encode::serialize;
2use elements::{
3 bitcoin, confidential, AssetIssuance, PeginData, PegoutData, Transaction, TxIn, TxInWitness,
4 TxOut, TxOutWitness, Txid, Wtxid, Script, Address,
5};
6use elements::secp256k1_zkp::{RangeProof, SurjectionProof};
7
8use serde::{Deserialize, Serialize};
9
10use ::{GetInfo, Network, HexBytes};
11
12use confidential::{ConfidentialAssetInfo, ConfidentialNonceInfo, ConfidentialValueInfo};
13
14const BTCNET: elements::bitcoin::Network = elements::bitcoin::Network::Bitcoin;
15
16#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
17pub struct AssetIssuanceInfo {
18 pub asset_blinding_nonce: Option<HexBytes>,
19 pub asset_entropy: Option<HexBytes>,
20 pub amount: Option<ConfidentialValueInfo>,
21 pub inflation_keys: Option<ConfidentialValueInfo>,
22}
23
24impl GetInfo<AssetIssuanceInfo> for AssetIssuance {
25 fn get_info(&self, network: Network) -> AssetIssuanceInfo {
26 AssetIssuanceInfo {
27 asset_blinding_nonce: Some(self.asset_blinding_nonce[..].into()),
28 asset_entropy: Some(self.asset_entropy[..].into()),
29 amount: Some(self.amount.get_info(network)),
30 inflation_keys: Some(self.inflation_keys.get_info(network)),
31 }
32 }
33}
34
35#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
36pub struct PeginDataInfo {
37 pub outpoint: String,
38 pub value: u64,
39 pub asset: ConfidentialAssetInfo,
40 pub genesis_hash: bitcoin::BlockHash,
41 pub claim_script: HexBytes,
42 pub mainchain_tx_hex: HexBytes,
43 pub mainchain_tx: Option<hal::tx::TransactionInfo>,
44 pub merkle_proof: HexBytes,
45 pub referenced_block: bitcoin::BlockHash,
46}
47
48impl<'tx> GetInfo<PeginDataInfo> for PeginData<'tx> {
49 fn get_info(&self, network: Network) -> PeginDataInfo {
50 PeginDataInfo {
51 outpoint: self.outpoint.to_string(),
52 value: self.value,
53 asset: self.asset.get_info(network),
54 genesis_hash: self.genesis_hash,
55 claim_script: self.claim_script.into(),
56 mainchain_tx_hex: self.tx.into(),
57 mainchain_tx: match bitcoin::consensus::encode::deserialize::<bitcoin::Transaction>(&self.tx) {
58 Ok(tx) => Some(hal::GetInfo::get_info(&tx, BTCNET)),
59 Err(_) => None,
60 },
61 merkle_proof: self.merkle_proof.into(),
62 referenced_block: self.referenced_block,
63 }
64 }
65}
66
67#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
68pub struct InputWitnessInfo {
69 pub amount_rangeproof: Option<HexBytes>,
70 pub inflation_keys_rangeproof: Option<HexBytes>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub script_witness: Option<Vec<HexBytes>>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub pegin_witness: Option<Vec<HexBytes>>,
75}
76
77impl GetInfo<InputWitnessInfo> for TxInWitness {
78 fn get_info(&self, _network: Network) -> InputWitnessInfo {
79 InputWitnessInfo {
80 amount_rangeproof: self.amount_rangeproof.as_ref().map(|r| RangeProof::serialize(r).into()),
81 inflation_keys_rangeproof: self.inflation_keys_rangeproof.as_ref().map(|r| RangeProof::serialize(r).into()),
82 script_witness: if self.script_witness.len() > 0 {
83 Some(self.script_witness.iter().map(|w| w.clone().into()).collect())
84 } else {
85 None
86 },
87 pegin_witness: if self.pegin_witness.len() > 0 {
88 Some(self.pegin_witness.iter().map(|w| w.clone().into()).collect())
89 } else {
90 None
91 },
92 }
93 }
94}
95
96#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
97pub struct InputScriptInfo {
98 pub hex: Option<::HexBytes>,
99 pub asm: Option<String>,
100}
101
102pub struct InputScript<'a>(pub &'a Script);
103
104impl<'a> ::GetInfo<InputScriptInfo> for InputScript<'a> {
105 fn get_info(&self, _network: Network) -> InputScriptInfo {
106 InputScriptInfo {
107 hex: Some(self.0.to_bytes().into()),
108 asm: Some(self.0.asm()),
109 }
110 }
111}
112
113#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
114pub struct InputInfo {
115 pub prevout: Option<String>,
116 pub txid: Option<Txid>,
117 pub vout: Option<u32>,
118 pub script_sig: Option<InputScriptInfo>,
119 pub sequence: Option<u32>,
120
121 pub is_pegin: Option<bool>,
122 pub has_issuance: Option<bool>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub asset_issuance: Option<AssetIssuanceInfo>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub witness: Option<InputWitnessInfo>,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub pegin_data: Option<PeginDataInfo>,
130}
131
132impl GetInfo<InputInfo> for TxIn {
133 fn get_info(&self, network: Network) -> InputInfo {
134 InputInfo {
135 prevout: Some(format!("{}:{}", self.previous_output.txid, self.previous_output.vout)),
137 txid: Some(self.previous_output.txid),
138 vout: Some(self.previous_output.vout),
139 sequence: Some(self.sequence.to_consensus_u32()),
140 script_sig: Some(::GetInfo::get_info(&InputScript(&self.script_sig), network)),
141
142 is_pegin: Some(self.is_pegin),
143 has_issuance: Some(self.has_issuance()),
144 asset_issuance: if self.has_issuance() {
145 Some(self.asset_issuance.get_info(network))
146 } else {
147 None
148 },
149 witness: if !self.witness.is_empty() {
150 Some(self.witness.get_info(network))
151 } else {
152 None
153 },
154 pegin_data: self.pegin_data().map(|p| p.get_info(network)),
155 }
156 }
157}
158
159#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
160pub struct PegoutDataInfo {
161 pub value: u64,
162 pub asset: ConfidentialAssetInfo,
163 pub genesis_hash: bitcoin::BlockHash,
164 pub script_pub_key: hal::tx::OutputScriptInfo,
165 pub extra_data: Vec<HexBytes>,
166}
167
168impl<'tx> GetInfo<PegoutDataInfo> for PegoutData<'tx> {
169 fn get_info(&self, network: Network) -> PegoutDataInfo {
170 PegoutDataInfo {
171 value: self.value,
172 asset: self.asset.get_info(network),
173 genesis_hash: self.genesis_hash,
174 script_pub_key: hal::GetInfo::get_info(&hal::tx::OutputScript(&self.script_pubkey), BTCNET),
175 extra_data: self.extra_data.iter().map(|w| w.clone().into()).collect(),
176 }
177 }
178}
179
180#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
181pub struct OutputWitnessInfo {
182 pub surjection_proof: Option<HexBytes>,
183 pub rangeproof: Option<HexBytes>,
184}
185
186impl GetInfo<OutputWitnessInfo> for TxOutWitness {
187 fn get_info(&self, _network: Network) -> OutputWitnessInfo {
188 OutputWitnessInfo {
189 surjection_proof: self.surjection_proof.as_ref().map(|p| SurjectionProof::serialize(p).into()),
190 rangeproof: self.rangeproof.as_ref().map(|p| RangeProof::serialize(p).into()),
191 }
192 }
193}
194
195#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
196pub struct OutputScriptInfo {
197 pub hex: Option<::HexBytes>,
198 pub asm: Option<String>,
199 #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
200 pub type_: Option<String>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub address: Option<Address>,
203}
204
205pub struct OutputScript<'a>(pub &'a Script);
206
207impl<'a> ::GetInfo<OutputScriptInfo> for OutputScript<'a> {
208 fn get_info(&self, network: Network) -> OutputScriptInfo {
209 OutputScriptInfo {
210 hex: Some(self.0.to_bytes().into()),
211 asm: Some(self.0.asm()),
212 type_: Some(
213 if self.0.is_p2pk() {
214 "p2pk"
215 } else if self.0.is_p2pkh() {
216 "p2pkh"
217 } else if self.0.is_op_return() {
218 "opreturn"
219 } else if self.0.is_p2sh() {
220 "p2sh"
221 } else if self.0.is_v0_p2wpkh() {
222 "p2wpkh"
223 } else if self.0.is_v0_p2wsh() {
224 "p2wsh"
225 } else {
226 "unknown"
227 }
228 .to_owned(),
229 ),
230 address: Address::from_script(&self.0, None, network.address_params()),
231 }
232 }
233}
234
235
236#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
237pub struct OutputInfo {
238 pub script_pub_key: Option<OutputScriptInfo>,
239
240 pub asset: Option<ConfidentialAssetInfo>,
241 pub value: Option<ConfidentialValueInfo>,
242 pub nonce: Option<ConfidentialNonceInfo>,
243 pub witness: Option<OutputWitnessInfo>,
244 pub is_fee: Option<bool>,
245
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub pegout_data: Option<PegoutDataInfo>,
248}
249
250impl GetInfo<OutputInfo> for TxOut {
251 fn get_info(&self, network: Network) -> OutputInfo {
252 let is_fee = {
253 let exp_ass = match self.asset {
256 confidential::Asset::Explicit(_) => true,
257 _ => false,
258 };
259 let exp_val = match self.value {
260 confidential::Value::Explicit(_) => true,
261 _ => false,
262 };
263
264 exp_ass && exp_val && self.script_pubkey.len() == 0
265 };
266
267 OutputInfo {
268 script_pub_key: Some(::GetInfo::get_info(&OutputScript(&self.script_pubkey), network)),
269 asset: Some(self.asset.get_info(network)),
270 value: Some(self.value.get_info(network)),
271 nonce: Some(self.nonce.get_info(network)),
272 witness: Some(self.witness.get_info(network)),
273 is_fee: Some(is_fee),
274 pegout_data: self.pegout_data().map(|p| p.get_info(network)),
275 }
276 }
277}
278
279#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
280pub struct TransactionInfo {
281 pub txid: Option<Txid>,
282 pub wtxid: Option<Wtxid>,
283 pub hash: Option<Wtxid>,
284 pub size: Option<usize>,
285 pub weight: Option<usize>,
286 pub vsize: Option<usize>,
287 pub version: Option<u32>,
288 pub locktime: Option<u32>,
289 pub inputs: Option<Vec<InputInfo>>,
290 pub outputs: Option<Vec<OutputInfo>>,
291}
292
293impl GetInfo<TransactionInfo> for Transaction {
294 fn get_info(&self, network: Network) -> TransactionInfo {
295 TransactionInfo {
296 txid: Some(self.txid()),
297 wtxid: Some(self.wtxid()),
298 hash: Some(self.wtxid()),
299 version: Some(self.version),
300 locktime: Some(self.lock_time.to_u32()),
301 size: Some(serialize(self).len()),
302 weight: Some(self.weight() as usize),
303 vsize: Some((self.weight() / 4) as usize),
304 inputs: Some(self.input.iter().map(|i| i.get_info(network)).collect()),
305 outputs: Some(self.output.iter().map(|o| o.get_info(network)).collect()),
306 }
307 }
308}