1use elements_miniscript::elements::{self, BlockHeader};
2
3use elements::bitcoin::bip32::Xpriv;
4use elements::bitcoin::Network;
5use elements::confidential::{AssetBlindingFactor, ValueBlindingFactor};
6use elements::encode::Decodable;
7use elements::hex::{FromHex, ToHex};
8use elements::pset::PartiallySignedTransaction;
9use elements::{AssetId, TxOutWitness, Txid};
10use elements::{Block, TxOutSecrets};
11use elements_miniscript::descriptor::checksum::desc_checksum;
12use pulldown_cmark::{CodeBlockKind, Event, Tag};
13use rand::{thread_rng, Rng};
14use std::str::FromStr;
15
16mod registry;
17mod test_env;
18mod waterfalls;
19pub use test_env::{TestEnv, TestEnvBuilder};
20
21const DEFAULT_FEE_RATE: f32 = 100.0;
22
23pub const TEST_MNEMONIC: &str =
24 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
25pub const TEST_MNEMONIC_XPUB: &str =
26"tpubD6NzVbkrYhZ4XYa9MoLt4BiMZ4gkt2faZ4BcmKu2a9te4LDpQmvEz2L2yDERivHxFPnxXXhqDRkUNnQCpZggCyEZLBktV7VaSmwayqMJy1s";
27pub const TEST_MNEMONIC_SLIP77: &str =
28 "9c8e4f05c7711a98c838be228bcb84924d4570ca53f35fa1c793e58841d47023";
29
30pub const DEFAULT_SPECULOS_MNEMONIC: &str = "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster seven myth punch hobby comfort wild raise skin";
31
32pub const FED_PEG_SCRIPT: &str = "5b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc401021031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb2103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5fae736402c00fb269522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb53ae68";
48pub const FED_PEG_SCRIPT_ASM: &str = "OP_PUSHNUM_11 OP_PUSHBYTES_33 020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261 OP_PUSHBYTES_33 02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99 OP_PUSHBYTES_33 02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48 OP_PUSHBYTES_33 029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c OP_PUSHBYTES_33 02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010 OP_PUSHBYTES_33 031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb OP_PUSHBYTES_33 03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b OP_PUSHBYTES_33 03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2 OP_PUSHBYTES_33 0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174 OP_PUSHBYTES_33 03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1 OP_PUSHBYTES_33 035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6 OP_PUSHBYTES_33 03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c OP_PUSHBYTES_33 03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546 OP_PUSHBYTES_33 03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828 OP_PUSHBYTES_33 03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a OP_PUSHNUM_15 OP_CHECKMULTISIG OP_IFDUP OP_NOTIF OP_PUSHBYTES_2 c00f OP_CSV OP_VERIFY OP_PUSHNUM_2 OP_PUSHBYTES_33 03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79 OP_PUSHBYTES_33 0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807 OP_PUSHBYTES_33 0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb OP_PUSHNUM_3 OP_CHECKMULTISIG OP_ENDIF";
49pub const FED_PEG_DESC: &str = "wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb))))#7jwwklk4";
50
51pub const PEGIN_TEST_DESC: &str = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/<0;1>/*))";
52pub const PEGIN_TEST_ADDR: &str = "tb1qqkq6czql4zqwsylgrfzttjrn5wjeqmwfq5yn80p39amxtnkng9lsyjwm6v"; pub const TEST_DESCRIPTOR: &str = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/<0;1>/*))#cch6wrnp";
56
57pub fn liquid_block_1() -> Block {
58 let raw = include_bytes!(
59 "../test_data/afafbbdfc52a45e51a3b634f391f952f6bdfd14ef74b34925954b4e20d0ad639.raw"
60 );
61 Block::consensus_decode(&raw[..]).unwrap()
62}
63
64pub fn liquid_block_header_2_963_520() -> BlockHeader {
65 let hex = include_str!("../test_data/block_header_2_963_520.hex");
66 let bytes = Vec::<u8>::from_hex(hex).unwrap();
67 BlockHeader::consensus_decode(&bytes[..]).unwrap()
68}
69
70pub fn add_checksum(desc: &str) -> String {
71 if desc.find('#').is_some() {
72 desc.into()
73 } else {
74 format!("{}#{}", desc, desc_checksum(desc).unwrap())
75 }
76}
77
78pub fn compute_fee_rate_without_discount_ct(pset: &PartiallySignedTransaction) -> f32 {
79 let vsize = pset.extract_tx().unwrap().vsize();
80 let fee_satoshi = pset.outputs().last().unwrap().amount.unwrap();
81 1000.0 * (fee_satoshi as f32 / vsize as f32)
82}
83
84pub fn compute_fee_rate(pset: &PartiallySignedTransaction) -> f32 {
85 let vsize = pset.extract_tx().unwrap().discount_vsize();
86 let fee_satoshi = pset.outputs().last().unwrap().amount.unwrap();
87 1000.0 * (fee_satoshi as f32 / vsize as f32)
88}
89
90pub fn assert_fee_rate(fee_rate: f32, expected: Option<f32>) {
91 let expected = expected.unwrap_or(DEFAULT_FEE_RATE);
92 let toll = 0.45;
93 assert!(fee_rate > expected * (1.0 - toll));
94 assert!(fee_rate < expected * (1.0 + toll));
95}
96
97pub fn parse_code_from_markdown(markdown_input: &str, code_kind: &str) -> Vec<String> {
98 let parser = pulldown_cmark::Parser::new(markdown_input);
99 let mut result = vec![];
100 let mut str = String::new();
101 let mut active = false;
102
103 for el in parser {
104 match el {
105 Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(current)))
106 if code_kind == current.as_ref() =>
107 {
108 active = true
109 }
110 Event::Text(t) => {
111 if active {
112 str.push_str(t.as_ref())
113 }
114 }
115 Event::End(Tag::CodeBlock(CodeBlockKind::Fenced(current)))
116 if code_kind == current.as_ref() =>
117 {
118 result.push(str.clone());
119 str.clear();
120 active = false;
121 }
122 _ => (),
123 }
124 }
125
126 result
127}
128
129pub fn pset_rt(pset: &PartiallySignedTransaction) -> PartiallySignedTransaction {
134 PartiallySignedTransaction::from_str(&pset.to_string()).unwrap()
135}
136
137pub fn regtest_policy_asset() -> AssetId {
138 AssetId::from_str("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225").unwrap()
139}
140
141pub fn init_logging() {
142 let _ = env_logger::try_init();
143}
144
145#[allow(dead_code)]
146pub fn prune_proofs(pset: &PartiallySignedTransaction) -> PartiallySignedTransaction {
147 let mut pset = pset.clone();
148 for i in pset.inputs_mut() {
149 if let Some(utxo) = &mut i.witness_utxo {
150 utxo.witness = TxOutWitness::default();
151 }
152 if let Some(tx) = &mut i.non_witness_utxo {
153 tx.output
154 .iter_mut()
155 .for_each(|o| o.witness = Default::default());
156 }
157 }
158 for o in pset.outputs_mut() {
159 o.value_rangeproof = None;
160 o.asset_surjection_proof = None;
161 o.blind_value_proof = None;
162 o.blind_asset_proof = None;
163 }
164 pset
165}
166
167pub fn generate_mnemonic() -> String {
168 let mut bytes = [0u8; 16];
169 thread_rng().fill(&mut bytes);
170 bip39::Mnemonic::from_entropy(&bytes).unwrap().to_string()
171}
172
173pub fn generate_slip77() -> String {
174 let mut bytes = [0u8; 32];
175 thread_rng().fill(&mut bytes);
176 bytes.to_hex()
177}
178
179pub fn generate_view_key() -> String {
180 let mut bytes = [0u8; 32];
181 thread_rng().fill(&mut bytes);
182 bytes.to_hex()
183}
184
185pub fn generate_xprv() -> Xpriv {
186 let mut seed = [0u8; 16];
187 thread_rng().fill(&mut seed);
188 Xpriv::new_master(Network::Regtest, &seed).unwrap()
189}
190
191pub fn n_issuances(details: &lwk_common::PsetDetails) -> usize {
192 details.issuances.iter().filter(|e| e.is_issuance()).count()
193}
194
195pub fn n_reissuances(details: &lwk_common::PsetDetails) -> usize {
196 details
197 .issuances
198 .iter()
199 .filter(|e| e.is_reissuance())
200 .count()
201}
202
203pub fn asset_blinding_factor_test_vector() -> AssetBlindingFactor {
204 AssetBlindingFactor::from_hex(
205 "0000000000000000000000000000000000000000000000000000000000000001",
206 )
207 .unwrap()
208}
209
210pub fn value_blinding_factor_test_vector() -> ValueBlindingFactor {
211 ValueBlindingFactor::from_hex(
212 "0000000000000000000000000000000000000000000000000000000000000002",
213 )
214 .unwrap()
215}
216
217pub fn txid_test_vector() -> Txid {
218 Txid::from_str("0000000000000000000000000000000000000000000000000000000000000003").unwrap()
219}
220
221pub fn tx_out_secrets_test_vector() -> TxOutSecrets {
222 elements::TxOutSecrets::new(
223 regtest_policy_asset(),
224 asset_blinding_factor_test_vector(),
225 1000,
226 value_blinding_factor_test_vector(),
227 )
228}
229
230pub fn tx_out_secrets_test_vector_bytes() -> Vec<u8> {
231 Vec::<u8>::from_hex(include_str!("../test_data/tx_out_secrets_test_vector.hex")).unwrap()
232}
233
234pub fn update_test_vector_bytes() -> Vec<u8> {
235 Vec::<u8>::from_hex(include_str!("../test_data/update_test_vector.hex")).unwrap()
236}
237
238pub fn update_test_vector_v1_bytes() -> Vec<u8> {
239 Vec::<u8>::from_hex(include_str!("../test_data/update_test_vector_v1.hex")).unwrap()
240}
241
242pub fn update_test_vector_2_bytes() -> Vec<u8> {
243 include_bytes!("../test_data/update_test_vector.bin").to_vec()
244}
245
246pub fn update_test_vector_many_transactions() -> Vec<u8> {
248 include_bytes!("../test_data/update_many_txs.bin").to_vec()
249}
250
251pub fn update_v2_test_vector_after_many_transactions() -> Vec<u8> {
253 include_bytes!("../test_data/update_v2_after_many_txs.bin").to_vec()
254}
255
256pub fn update_merge_test_1() -> Vec<u8> {
259 include_bytes!("../test_data/merge_updates/update_merge_1.bin").to_vec()
260}
261
262pub fn update_merge_test_2() -> Vec<u8> {
265 include_bytes!("../test_data/merge_updates/update_merge_2.bin").to_vec()
266}
267
268pub fn update_merge_test_3() -> Vec<u8> {
271 include_bytes!("../test_data/merge_updates/update_merge_3.bin").to_vec()
272}
273
274pub fn update_merge_test_descriptor() -> String {
276 include_str!("../test_data/merge_updates/descriptor.txt").to_string()
277}
278
279pub fn update_test_vector_encrypted_bytes() -> Vec<u8> {
280 Vec::<u8>::from_hex(include_str!(
281 "../test_data/update_test_vector_encrypted.hex"
282 ))
283 .unwrap()
284}
285
286pub fn update_test_vector_encrypted_base64() -> String {
287 include_str!("../test_data/update_test_vector/update.base64").to_string()
288}
289
290pub fn update_test_vector_encrypted_bytes2() -> Vec<u8> {
291 include_bytes!("../test_data/update_test_vector/000000000000").to_vec()
292}
293
294pub fn wollet_descriptor_string2() -> String {
295 include_str!("../test_data/update_test_vector/desc").to_string()
296}
297
298pub fn wollet_descriptor_string() -> String {
299 include_str!("../test_data/update_test_vector/desc2").to_string()
300}
301
302pub fn wollet_descriptor_many_transactions() -> &'static str {
303 "ct(slip77(ac53739ddde9fdf6bba3dbc51e989b09aa8c9cdce7b7d7eddd49cec86ddf71f7),elwpkh([93970d14/84'/1'/0']tpubDC3BrFCCjXq4jAceV8k6UACxDDJCFb1eb7R7BiKYUGZdNagEhNfJoYtUrRdci9JFs1meiGGModvmNm8PrqkrEjJ6mpt6gA1DRNU8vu7GqXH/<0;1>/*))#u0y4axgs"
304}
305
306pub fn psets_to_combine() -> (String, Vec<PartiallySignedTransaction>) {
308 let c = |s: &str| PartiallySignedTransaction::from_str(s).unwrap();
309 let ps = vec![
310 c(include_str!("../test_data/pset_combine/s1_pset.base64")),
311 c(include_str!("../test_data/pset_combine/s2_pset.base64")),
312 c(include_str!("../test_data/pset_combine/s3_pset.base64")),
313 c(include_str!("../test_data/pset_combine/s4_pset.base64")),
314 c(include_str!("../test_data/pset_combine/s5_pset.base64")),
315 ];
316 let d = include_str!("../test_data/pset_combine/desc");
317 (d.to_string(), ps)
318}
319
320pub fn descriptor_pset_usdt_no_contracts() -> &'static str {
321 include_str!("../test_data/pset_usdt/desc")
322}
323
324pub fn pset_usdt_no_contracts() -> &'static str {
326 include_str!("../test_data/pset_usdt/pset_usdt_no_contracts.base64")
327}
328
329pub fn pset_usdt_with_contract() -> &'static str {
330 include_str!("../test_data/pset_usdt/pset_usdt_with_contract.base64")
331}
332
333#[cfg(test)]
334mod test {
335
336 use crate::parse_code_from_markdown;
337
338 #[test]
339 fn test_parse_code_from_markdown() {
340 let mkdown = r#"
341```python
342python
343code
344```
345```rust
346rust
347code
348```
349
350```python
351some more
352python code
353"#;
354 let res = parse_code_from_markdown(mkdown, "python");
355 assert_eq!(
356 res,
357 vec![
358 "python\ncode\n".to_string(),
359 "some more\npython code\n".to_string()
360 ]
361 );
362
363 let res = parse_code_from_markdown(mkdown, "rust");
364 assert_eq!(res, vec!["rust\ncode\n".to_string()])
365 }
366}