1use bitcoin::blockdata::opcodes::all as opcodes;
4use bitcoin::blockdata::script;
5use bitcoin::script::Instruction;
6use bitcoin::{Sequence, TxIn};
7use std::{error, fmt};
8
9use crate::script::{
10 instructions_as_vec, Multisig, PubKeyInfo, PublicKey, Signature, SignatureInfo,
11};
12
13pub const TAPROOT_ANNEX_INDICATOR: u8 = 0x50;
14pub const TAPROOT_LEAF_TAPSCRIPT: u8 = 0xc0;
15pub const TAPROOT_LEAF_MASK: u8 = 0xfe;
16pub const ORDINALS_INSCRIPTION_MARKER: [u8; 3] = [0x6f, 0x72, 0x64]; #[derive(Clone, Debug)]
19pub enum InputError {
20 TypeInfo(script::Error),
21 MultisigInfo(script::Error),
22 SignatureInfo(script::Error),
23 PubkeyInfo(script::Error),
24 SigOpsInfo(script::Error),
25 ScriptHashInfo(script::Error),
26}
27
28impl fmt::Display for InputError {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 match self {
31 InputError::TypeInfo(e) => write!(f, "Could not determine type of input: {}", e),
32 InputError::MultisigInfo(e) => {
33 write!(f, "Could not extract multisig infos from input: {}", e)
34 }
35 InputError::SignatureInfo(e) => {
36 write!(f, "Could not extract signature infos from input: {}", e)
37 }
38 InputError::PubkeyInfo(e) => {
39 write!(f, "Could not extract pubkey infos from input: {}", e)
40 }
41 InputError::SigOpsInfo(e) => {
42 write!(f, "Could not extract sigops infos from input: {}", e)
43 }
44 InputError::ScriptHashInfo(e) => {
45 write!(f, "Could not extract sighash infos from input: {}", e)
46 }
47 }
48 }
49}
50
51impl error::Error for InputError {
52 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
53 match *self {
54 InputError::TypeInfo(ref e) => Some(e),
55 InputError::MultisigInfo(ref e) => Some(e),
56 InputError::SignatureInfo(ref e) => Some(e),
57 InputError::PubkeyInfo(ref e) => Some(e),
58 InputError::SigOpsInfo(ref e) => Some(e),
59 InputError::ScriptHashInfo(ref e) => Some(e),
60 }
61 }
62}
63
64#[derive(Debug)]
65pub struct InputInfo {
66 pub in_type: InputType,
67 pub sequence: Sequence,
68 pub multisig_info: Option<MultisigInputInfo>,
69 pub signature_info: Vec<SignatureInfo>,
70 pub pubkey_stats: Vec<PubKeyInfo>,
71 }
74
75impl InputInfo {
76 pub fn new(input: &TxIn) -> Result<InputInfo, InputError> {
77 Ok(InputInfo {
78 sequence: input.sequence,
79 in_type: input.get_type()?,
80 multisig_info: input.multisig_info()?,
81 signature_info: SignatureInfo::all_from(input)?,
82 pubkey_stats: PubKeyInfo::from_input(input)?,
83 })
84 }
85
86 pub fn is_spending_segwit(&self) -> bool {
88 match self.in_type {
89 InputType::P2shP2wpkh
90 | InputType::P2shP2wsh
91 | InputType::P2wpkh
92 | InputType::P2wsh
93 | InputType::P2trkp
94 | InputType::P2trsp
95 | InputType::P2a => true,
96 InputType::P2ms
97 | InputType::P2msLaxDer
98 | InputType::P2pk
99 | InputType::P2pkLaxDer
100 | InputType::P2pkh
101 | InputType::P2pkhLaxDer
102 | InputType::P2sh
103 | InputType::Unknown
104 | InputType::Coinbase
105 | InputType::CoinbaseWitness => false,
106 }
107 }
108
109 pub fn is_spending_taproot(&self) -> bool {
111 match self.in_type {
112 InputType::P2trkp | InputType::P2trsp => true,
113 InputType::P2ms
114 | InputType::P2msLaxDer
115 | InputType::P2pk
116 | InputType::P2pkLaxDer
117 | InputType::P2pkh
118 | InputType::P2pkhLaxDer
119 | InputType::P2sh
120 | InputType::Unknown
121 | InputType::P2shP2wpkh
122 | InputType::P2shP2wsh
123 | InputType::P2wpkh
124 | InputType::P2wsh
125 | InputType::P2a
126 | InputType::Coinbase
127 | InputType::CoinbaseWitness => false,
128 }
129 }
130
131 pub fn is_spending_nested_segwit(&self) -> bool {
133 match self.in_type {
134 InputType::P2shP2wpkh | InputType::P2shP2wsh => true,
135 InputType::P2pk
136 | InputType::P2pkLaxDer
137 | InputType::P2pkh
138 | InputType::P2pkhLaxDer
139 | InputType::P2ms
140 | InputType::P2msLaxDer
141 | InputType::P2wpkh
142 | InputType::P2wsh
143 | InputType::P2trkp
144 | InputType::P2trsp
145 | InputType::P2sh
146 | InputType::P2a
147 | InputType::Coinbase
148 | InputType::Unknown
149 | InputType::CoinbaseWitness => false,
150 }
151 }
152
153 pub fn is_spending_native_segwit(&self) -> bool {
155 match self.in_type {
156 InputType::P2wpkh
157 | InputType::P2wsh
158 | InputType::P2trkp
159 | InputType::P2trsp
160 | InputType::P2a => true,
161 InputType::P2pk
162 | InputType::P2pkLaxDer
163 | InputType::P2pkh
164 | InputType::P2pkhLaxDer
165 | InputType::P2ms
166 | InputType::P2msLaxDer
167 | InputType::P2shP2wsh
168 | InputType::P2shP2wpkh
169 | InputType::P2sh
170 | InputType::Coinbase
171 | InputType::Unknown
172 | InputType::CoinbaseWitness => false,
173 }
174 }
175
176 pub fn is_spending_legacy(&self) -> bool {
178 match self.in_type {
179 InputType::P2ms
180 | InputType::P2msLaxDer
181 | InputType::P2pk
182 | InputType::P2pkLaxDer
183 | InputType::P2pkh
184 | InputType::P2pkhLaxDer
185 | InputType::P2sh
186 | InputType::Unknown => true,
187 InputType::P2wpkh
188 | InputType::P2wsh
189 | InputType::P2trkp
190 | InputType::P2trsp
191 | InputType::P2shP2wpkh
192 | InputType::P2shP2wsh
193 | InputType::P2a
194 | InputType::Coinbase
195 | InputType::CoinbaseWitness => false,
196 }
197 }
198
199 pub fn is_spending_multisig(&self) -> bool {
201 self.multisig_info.is_some()
202 }
203}
204
205#[derive(PartialEq, Eq, Debug, Clone)]
207pub struct MultisigInputInfo {
208 pub m_of_n: (u8, u8),
213 pub unknown_n: bool,
217}
218
219pub trait InputMultisigDetection {
220 fn multisig_info(&self) -> Result<Option<MultisigInputInfo>, InputError>;
221}
222
223impl InputMultisigDetection for TxIn {
224 fn multisig_info(&self) -> Result<Option<MultisigInputInfo>, InputError> {
227 if self.is_scripthash_input()? {
228 if let Ok(Some(redeemscript)) = self.redeem_script() {
229 if let Ok(Some(multisig)) = redeemscript.get_opcheckmultisig_n_m() {
230 return Ok(Some(MultisigInputInfo {
231 m_of_n: multisig,
232 unknown_n: false,
233 }));
234 }
235 }
236 } else if self.get_type()? == InputType::P2ms {
237 if let Ok(instructions) = crate::script::instructions_as_vec(&self.script_sig) {
238 let instructions_count = instructions.len();
240 assert!(instructions_count <= 4);
241 return Ok(Some(MultisigInputInfo {
242 m_of_n: ((instructions_count - 1) as u8, 0),
243 unknown_n: true,
244 }));
245 }
246 }
247 Ok(None)
248 }
249}
250
251pub trait InputSigops {
252 fn sigops(&self) -> Result<usize, InputError>;
253}
254
255impl InputSigops for TxIn {
256 fn sigops(&self) -> Result<usize, InputError> {
257 const SIGOPS_SCALE_FACTOR: usize = 4;
258 let mut sigops: usize = 0;
259
260 if self.is_p2a()
262 || self.is_p2trkp()
263 || self.is_p2trsp()
264 || self.is_coinbase()
265 || self.is_coinbase_witness()
266 {
267 return Ok(0);
268 }
269
270 sigops += SIGOPS_SCALE_FACTOR * self.script_sig.count_sigops_legacy();
272
273 match self.get_type()? {
274 InputType::P2sh => {
276 if let Some(redeem_script) = self.redeem_script()? {
277 sigops += SIGOPS_SCALE_FACTOR * redeem_script.count_sigops();
278 }
279 }
280 InputType::P2shP2wsh | InputType::P2wsh => {
281 if let Some(redeem_script) = self.redeem_script()? {
282 sigops += redeem_script.count_sigops();
283 }
284 }
285 InputType::P2shP2wpkh | InputType::P2wpkh => {
287 sigops += 1;
288 }
289 _ => (),
290 };
291
292 Ok(sigops)
293 }
294}
295
296pub trait ScriptHashInput {
297 fn redeem_script(&self) -> Result<Option<bitcoin::ScriptBuf>, InputError>;
298}
299
300impl ScriptHashInput for TxIn {
301 fn redeem_script(&self) -> Result<Option<bitcoin::ScriptBuf>, InputError> {
304 if !self.is_scripthash_input()? {
305 return Ok(None);
306 }
307
308 match self.get_type()? {
309 InputType::P2sh => {
310 if let Some(instruction_result) = self.script_sig.instructions().last() {
312 let instruction = match instruction_result {
313 Ok(ins) => ins,
314 Err(e) => return Err(InputError::ScriptHashInfo(e)),
315 };
316 if let script::Instruction::PushBytes(push_bytes) = instruction {
317 return Ok(Some(bitcoin::ScriptBuf::from(
318 push_bytes.as_bytes().to_vec(),
319 )));
320 }
321 }
322 Ok(None)
323 }
324 InputType::P2shP2wsh => {
325 if let Some(bytes) = self.witness.last() {
327 return Ok(Some(bitcoin::ScriptBuf::from(bytes.to_vec())));
328 }
329 Ok(None)
330 }
331 InputType::P2wsh => {
332 if let Some(bytes) = self.witness.last() {
334 return Ok(Some(bitcoin::ScriptBuf::from(bytes.to_vec())));
335 }
336 Ok(None)
337 }
338 _ => Ok(None),
339 }
340 }
341}
342
343pub trait PubkeyInput {
344 fn get_pubkey(&self) -> bitcoin::Script;
345 fn get_signature(&self) -> bitcoin::Script;
346}
347
348pub trait InputTypeDetection {
349 fn get_type(&self) -> Result<InputType, InputError>;
350 fn has_witness(&self) -> bool;
351
352 fn is_scripthash_input(&self) -> Result<bool, InputError>;
353
354 fn is_p2ms(&self, strict_der_sig: bool) -> Result<bool, InputError>;
356 fn is_p2pk(&self, strict_der_sig: bool) -> Result<bool, InputError>;
357 fn is_p2pkh(&self, strict_der_sig: bool) -> Result<bool, InputError>;
358 fn is_p2sh(&self) -> Result<bool, InputError>;
359 fn is_nested_p2wpkh(&self) -> bool;
360 fn is_nested_p2wsh(&self) -> bool;
361 fn is_p2wpkh(&self) -> bool;
362 fn is_p2wsh(&self) -> bool;
363 fn is_p2trkp(&self) -> bool;
364 fn is_p2trsp(&self) -> bool;
365 fn is_p2a(&self) -> bool;
366 fn is_coinbase(&self) -> bool;
367 fn is_coinbase_witness(&self) -> bool;
368}
369
370#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
371pub enum InputType {
372 P2pk,
374 P2pkLaxDer,
378 P2pkh,
380 P2pkhLaxDer,
384 P2shP2wpkh,
386 P2wpkh,
388 P2ms,
390 P2msLaxDer,
394 P2sh,
396 P2shP2wsh,
398 P2wsh,
400 P2trkp,
402 P2trsp,
404 P2a,
406 Coinbase,
408 CoinbaseWitness,
410 Unknown,
412}
413
414impl fmt::Display for InputType {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 match self {
417 InputType::P2pk => write!(f, "P2PK"),
418 InputType::P2pkLaxDer => write!(f, "P2PK (lax DER)"),
419 InputType::P2pkh => write!(f, "P2PKH"),
420 InputType::P2pkhLaxDer => write!(f, "P2PKH (lax DER)"),
421 InputType::P2shP2wpkh => write!(f, "P2SH-P2WPKH"),
422 InputType::P2wpkh => write!(f, "P2WPKH"),
423 InputType::P2msLaxDer => write!(f, "P2MS (lax DER)"),
424 InputType::P2ms => write!(f, "P2MS"),
425 InputType::P2sh => write!(f, "P2SH"),
426 InputType::P2shP2wsh => write!(f, "P2SH-P2WSH"),
427 InputType::P2wsh => write!(f, "P2WSH"),
428 InputType::P2trkp => write!(f, "P2TR key-path"),
429 InputType::P2trsp => write!(f, "P2TR script-path"),
430 InputType::P2a => write!(f, "P2A"),
431 InputType::Coinbase => write!(f, "Coinbase"),
432 InputType::CoinbaseWitness => write!(f, "Coinbase with Witness"),
433 InputType::Unknown => write!(f, "UNKNOWN"),
434 }
435 }
436}
437
438impl InputTypeDetection for TxIn {
439 fn get_type(&self) -> Result<InputType, InputError> {
440 if self.has_witness() {
441 if self.is_coinbase_witness() {
445 return Ok(InputType::CoinbaseWitness);
446 } else if self.is_nested_p2wpkh() {
447 return Ok(InputType::P2shP2wpkh);
448 } else if self.is_p2wpkh() {
449 return Ok(InputType::P2wpkh);
450 } else if self.is_nested_p2wsh() {
451 return Ok(InputType::P2shP2wsh);
452 } else if self.is_p2wsh() {
453 return Ok(InputType::P2wsh);
454 } else if self.is_p2trkp() {
455 return Ok(InputType::P2trkp);
456 } else if self.is_p2trsp() {
457 return Ok(InputType::P2trsp);
458 }
459 } else if self.is_coinbase() {
462 return Ok(InputType::Coinbase);
463 } else if self.is_p2pkh(true)? {
464 return Ok(InputType::P2pkh);
465 } else if self.is_p2pkh(false)? {
466 return Ok(InputType::P2pkhLaxDer);
467 } else if self.is_p2sh()? {
468 return Ok(InputType::P2sh);
469 } else if self.is_p2pk(true)? {
470 return Ok(InputType::P2pk);
471 } else if self.is_p2pk(false)? {
472 return Ok(InputType::P2pkLaxDer);
473 } else if self.is_p2ms(true)? {
474 return Ok(InputType::P2ms);
475 } else if self.is_p2ms(false)? {
476 return Ok(InputType::P2msLaxDer);
477 } else if self.is_p2a() {
478 return Ok(InputType::P2a);
479 }
480 Ok(InputType::Unknown)
481 }
482
483 fn has_witness(&self) -> bool {
485 !self.witness.is_empty()
486 }
487
488 fn is_scripthash_input(&self) -> Result<bool, InputError> {
490 match self.get_type()? {
491 InputType::P2sh | InputType::P2shP2wsh | InputType::P2wsh => Ok(true),
492 _ => Ok(false),
493 }
494 }
495
496 fn is_p2pk(&self, strict_der_sig: bool) -> Result<bool, InputError> {
513 if self.has_witness() || self.script_sig.is_empty() {
514 return Ok(false);
515 }
516
517 let instructions = match crate::script::instructions_as_vec(&self.script_sig) {
518 Ok(ins) => ins,
519 Err(e) => return Err(InputError::TypeInfo(e)),
520 };
521 if instructions.len() != 1 || !instructions[0].is_ecdsa_signature(strict_der_sig) {
522 return Ok(false);
523 }
524
525 Ok(true)
526 }
527
528 fn is_p2ms(&self, strict_der_sig: bool) -> Result<bool, InputError> {
542 if self.has_witness() {
543 return Ok(false);
544 }
545
546 let instructions = match crate::script::instructions_as_vec(&self.script_sig) {
547 Ok(ins) => ins,
548 Err(e) => return Err(InputError::TypeInfo(e)),
549 };
550
551 if instructions.len() < 2 || instructions.len() > 4 {
552 return Ok(false);
553 }
554
555 for (i, instruction) in instructions.iter().enumerate() {
556 match i {
557 0 => {
558 if let script::Instruction::PushBytes(bytes) = instruction {
560 if !bytes.is_empty() {
561 return Ok(false);
562 };
563 } else {
564 return Ok(false);
565 };
566 }
567 1..=3 => {
568 if !instruction.is_ecdsa_signature(strict_der_sig) {
570 return Ok(false);
571 }
572 }
573 _ => return Ok(false),
574 }
575 }
576
577 Ok(true)
578 }
579
580 fn is_p2pkh(&self, strict_der_sig: bool) -> Result<bool, InputError> {
598 if self.has_witness() {
599 return Ok(false);
600 }
601
602 let instructions = match crate::script::instructions_as_vec(&self.script_sig) {
603 Ok(ins) => ins,
604 Err(e) => return Err(InputError::TypeInfo(e)),
605 };
606 if instructions.len() != 2
607 || !instructions[0].is_ecdsa_signature(strict_der_sig)
608 || !instructions[1].is_pubkey()
609 {
610 return Ok(false);
611 }
612
613 Ok(true)
614 }
615
616 fn is_p2sh(&self) -> Result<bool, InputError> {
627 if self.has_witness()
628 || self.is_p2pkh(false)?
629 || self.is_p2pk(false)?
630 || self.is_p2ms(false)?
631 || self.is_p2pkh(true)?
632 || self.is_p2pk(true)?
633 || self.is_p2ms(true)?
634 || self.is_coinbase()
635 || self.script_sig.is_empty()
636 {
637 return Ok(false);
638 }
639
640 Ok(true)
641 }
642
643 fn is_nested_p2wpkh(&self) -> bool {
652 if self.script_sig.len() != 23 || self.witness.len() != 2 {
653 return false;
654 }
655
656 let script_sig = self.script_sig.as_bytes();
657 if script_sig[0] == opcodes::OP_PUSHBYTES_22.to_u8()
658 && script_sig[1] == opcodes::OP_PUSHBYTES_0.to_u8()
659 && script_sig[2] == opcodes::OP_PUSHBYTES_20.to_u8()
660 && self.witness.to_vec()[0].is_ecdsa_signature(true)
661 && self.witness.to_vec()[1].is_pubkey()
662 {
663 return true;
664 }
665
666 false
667 }
668
669 fn is_nested_p2wsh(&self) -> bool {
679 if self.script_sig.len() != 35 || self.witness.is_empty() {
680 return false;
681 }
682
683 let script_sig = self.script_sig.as_bytes();
684 if script_sig[0] == opcodes::OP_PUSHBYTES_34.to_u8()
685 && script_sig[1] == opcodes::OP_PUSHBYTES_0.to_u8()
686 && script_sig[2] == opcodes::OP_PUSHBYTES_32.to_u8()
687 {
688 return true;
689 }
690 false
691 }
692
693 fn is_p2wpkh(&self) -> bool {
700 if !self.script_sig.is_empty() || self.witness.len() != 2 {
701 return false;
702 }
703
704 if self.witness.to_vec()[0].is_ecdsa_signature(true)
705 && self.witness.to_vec()[1].is_pubkey()
706 {
707 return true;
708 }
709
710 false
711 }
712
713 fn is_p2wsh(&self) -> bool {
719 if !self.script_sig.is_empty()
720 || !self.has_witness()
721 || self.is_p2wpkh()
722 || self.is_p2trkp()
723 || self.is_p2trsp()
724 {
725 return false;
726 }
727
728 true
729 }
730
731 fn is_p2trkp(&self) -> bool {
738 if !self.script_sig.is_empty() || !self.has_witness() || self.witness.len() > 2 {
739 return false;
740 }
741 if self.witness.len() == 1 {
742 return self.witness.to_vec()[0].is_schnorr_signature();
744 } else if self.witness.len() == 2 {
745 if !self.witness.to_vec()[1].is_empty()
747 && self.witness.to_vec()[1][0] == TAPROOT_ANNEX_INDICATOR
748 {
749 return self.witness.to_vec()[0].is_schnorr_signature();
750 }
751 }
752 false
753 }
754
755 fn is_p2trsp(&self) -> bool {
762 if !self.script_sig.is_empty() || !self.has_witness() || self.witness.len() < 2 {
763 return false;
764 }
765
766 let last_witness_element_index = self.witness.len() - 1;
767 let mut control_block_index = last_witness_element_index;
768 let witness_vec = self.witness.to_vec();
769
770 if !witness_vec[last_witness_element_index].is_empty()
772 && witness_vec[last_witness_element_index][0] == TAPROOT_ANNEX_INDICATOR
773 {
774 control_block_index -= 1;
775 }
776
777 let control_block = &witness_vec[control_block_index];
779 if control_block.len() < 1 + 32 || (control_block.len() - 1) % 32 != 0 {
780 return false;
781 }
782
783 if control_block[0] & TAPROOT_LEAF_MASK == TAPROOT_LEAF_TAPSCRIPT {
784 return true;
785 }
786
787 false
788 }
789
790 fn is_p2a(&self) -> bool {
794 self.script_sig.is_empty() && !self.has_witness()
795 }
796
797 fn is_coinbase(&self) -> bool {
802 !self.has_witness()
803 && self.previous_output.vout == 0xffffffff
804 && self.previous_output.is_null()
805 }
806
807 fn is_coinbase_witness(&self) -> bool {
814 self.has_witness()
815 && self.previous_output.vout == 0xffffffff
816 && self.previous_output.is_null()
817 }
818}
819
820pub trait InputInscriptionDetection {
821 fn reveals_inscription(&self) -> Result<bool, script::Error>;
822}
823
824impl InputInscriptionDetection for TxIn {
825 fn reveals_inscription(&self) -> Result<bool, script::Error> {
826 if !self.is_p2trsp() {
827 return Ok(false);
828 }
829 if let Some(tapscript) = self.witness.tapscript() {
831 if let Ok(instructions) = instructions_as_vec(tapscript) {
832 let mut instruction_iter = instructions.iter();
833 while let Some(instruction) = instruction_iter.next() {
834 if matches!(instruction, Instruction::PushBytes(bytes) if bytes.is_empty())
835 && matches!(instruction_iter.next(), Some(Instruction::Op(op)) if op == &opcodes::OP_IF)
836 && matches!(instruction_iter.next(), Some(Instruction::PushBytes(bytes)) if bytes.as_bytes() == ORDINALS_INSCRIPTION_MARKER.to_vec())
837 {
838 return Ok(true);
839 }
840 }
841 }
842 }
843 Ok(false)
844 }
845}
846
847#[cfg(test)]
848mod tests {
849 use super::{
850 InputInfo, InputInscriptionDetection, InputMultisigDetection, InputSigops, InputType,
851 InputTypeDetection, MultisigInputInfo,
852 };
853 use bitcoin::Transaction;
854
855 #[test]
856 fn reveals_inscription() {
857 let rawtx = hex::decode("02000000000101da5159649742d35e069f74724bb72cbb116415d72e11771a17420e2201d4ecf30000000000fdffffff0122020000000000002251201e6960b35d5da5c6c9ce0a18d989518bf546b4968a4ad046d9d664f5585f50440340ad42d4bec479e22866603b11048a64a3e5d366046d494278336798a51fd5fe5166221949e3025b25b505433ed871e20399fd82ffc867b70de8acef8e86f91f857e20318de3d918b6ca5ce115f5b00b3ed0b9c85ca7ebe8f0ccbe9de0e05e45de9293ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800387b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a224d4d5353222c22616d74223a22323030227d6821c1318de3d918b6ca5ce115f5b00b3ed0b9c85ca7ebe8f0ccbe9de0e05e45de929300000000").unwrap();
859 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
860 let in0 = &tx.input[0];
861 assert!(in0.is_p2trsp());
862 assert!(in0.reveals_inscription().unwrap());
863
864 let rawtx = hex::decode("02000000000101db7427b32d5755c1ea1fad429d87e6a641a2682e53c0c7cfaf3bec578c349b680000000000fdffffff022202000000000000225120f97a587234b7e22e7b5de2d61b1861e0c8774eedb9b48190fabe41b083d24926db06000000000000160014d02d8c6d6b2307d96bc2bf99e89acab7fb3a923003402817599a681318c55b335f5fb29e6755a4f23e345a8dc130cb1e478f2dec76f748378d279f5b82ca70587d91caff2f906146df28785931b09f186489f317c2add020287b98bfb98dd21a639ee15a8414e70f4bb5f8747961f4c2ef1596519d465db1ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d38004c897b2270223a2022746170222c20226f70223a2022646d742d6d696e74222c2022646570223a2022303161393235393934656563313435313261653935386466313761353231666437663835616636613731633132373061656332303432323866613661613336346930222c20227469636b223a20226e6174222c2022626c6b223a202231363934227d6821c1f7f702f2e97e53bd22500cc1207871e88abba8871df5495ad16f3c73a5d7460e00000000").unwrap();
866 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
867 let in0 = &tx.input[0];
868 assert!(in0.is_p2trsp());
869 assert!(in0.reveals_inscription().unwrap());
870 }
871
872 #[test]
873 fn input_type_detection_p2pk() {
874 let rawtx = hex::decode("0100000001169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f400000000484730440220576497b7e6f9b553c0aba0d8929432550e092db9c130aae37b84b545e7f4a36c022066cb982ed80608372c139d7bb9af335423d5280350fe3e06bd510e695480914f01ffffffff0100ca9a3b000000001976a914340cfcffe029e6935f4e4e5839a2ff5f29c7a57188ac00000000").unwrap();
876 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
877 let in0 = &tx.input[0];
878 assert!(in0.is_p2pk(true).unwrap());
879 assert_eq!(in0.get_type().unwrap(), InputType::P2pk);
880 }
881
882 #[test]
883 fn input_type_detection_p2pkh() {
884 let rawtx = hex::decode("01000000013e536ab65e20de9b57dd2859abd7289fd0452c3f5ac672b956d9c787d1933466230000006a47304402201b6e925baff25e8f9fda211f4319a0d9bc5add80d285db5609b882a80b4c50d002200e797a1435838df602634dd69e829bc884bc995aac77ea57ddf5c92e44dacc6f012103b773940906913e962d81b6c4d7c405212bf91ae736123eba7970859edefba84effffffff0188f40000000000001976a91408653d83a8bff4c66edd72921659326bd6ef04cc88ac00000000").unwrap();
886 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
887 let in0 = &tx.input[0];
888 assert!(in0.is_p2pkh(true).unwrap());
889 assert_eq!(in0.get_type().unwrap(), InputType::P2pkh);
890 }
891
892 #[test]
893 fn input_type_detection_nested_p2wpkh() {
894 let rawtx = hex::decode("020000000001017287da3eef7369c13bacb9fb92e7b1c3aabe04ead8d76b620c3966623fb1da510000000017160014ace9fb5f9aab3d34f272775424bbacd1132ff00effffffff01614804000000000017a91431ab116fe54444ef21c7656f3bb4bfe2520210fe8702473044022053c98f1e2f3dad4ad3e53c1f2e78a833a9e3bb0a47e592dc840312d053805c4602200bb65ecf01cb49d7506df37ff61141584c731c127973d4a651ab0f5cc5de04c60121029b8741cc06f098df1fad8f1fb920e1d610024b9f0190708b0dd777ba9cd1a55300000000").unwrap();
896 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
897 let in0 = &tx.input[0];
898 assert!(in0.is_nested_p2wpkh());
899 assert_eq!(in0.get_type().unwrap(), InputType::P2shP2wpkh);
900 }
901
902 #[test]
903 fn input_type_detection_p2wpkh() {
904 let rawtx = hex::decode("01000000000101ce73651d1ef6e687a66a76adbaf16741a205e7230bff0ae7259d36c478ec1a339a00000000ffffffff018a399c0000000000160014a14296a183d6e4c2f1696713a9db833e66fcb2d50247304402204da5741dab6897b961d996c0bdd0fed51f33afa54459769a81019d04a35fb1a802206f47143811a512a73b9d1112f5f0202740c554bf853fe18e2c72e58381c5452b012103e37b04cf32aa417e3ef25c0fe19faefcdbb6e6b2eaca38837dabc4c146cdc95000000000").unwrap();
906 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
907 let in0 = &tx.input[0];
908 assert!(in0.is_p2wpkh());
909 assert_eq!(in0.get_type().unwrap(), InputType::P2wpkh);
910 }
911
912 #[test]
913 fn input_type_detection_p2sh() {
914 let rawtx = hex::decode("0200000001b5d093fa119005dbb1e6efe4abae8352b9be31999dd498e2a4242d12a1bcac8800000000910047304402203c3e5cb8e6dd567804efb6f26523229ea67ed1f4529a35fd92a64407db790cce02201ba1f5173e792cc9e63769700e8f7673eae8ac705b58caa5931ec614f56f1acc014751210377622563e0110914888b7dc9364d6d341804aa0d7f09b3dea04f14a7dad104452103c71b40231260e990938f1be55bbf8c580832bcfdcb60a4e64139f12b313fe35552aefeffffff0258c70d00000000001976a914bab670335c428fe202157fb867dd06acca4ac25388ac5c2d53000000000017a914ad69347daeb1811224627597d5d8ebffa78c4c3e8700000000").unwrap();
916 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
917 let in0 = &tx.input[0];
918 assert!(in0.is_p2sh().unwrap());
919 assert_eq!(in0.get_type().unwrap(), InputType::P2sh);
920 }
921
922 #[test]
923 fn input_sigops_nonstandard_rsk_p2sh() {
924 let rawtx = hex::decode("0200000001e5af92d188010aa34910c71de4a55d6f142c0989a62af388b10bd8a33b54e86c00000000fd3803004830450221008b42e9089fd73cd1367d7963664314fd7affc434766b97ef35e57f10c764eca802204bdf578f5339448053cc077b410050ca95f54f0773d1be37e4c8f7028b5b630d014730440220599fa798537dbca65defc998088b56df77993914f7b1f6d262ae210c49caf00a022013f11bc2c85befdcf36aac357e0d1cd9cd1954ccbbe6c90c56575b5e68dbb17401473044022040cf3f17bb5639e9a64c89566b21a13339e362ef27f02ac3bdd09a79b5564a4402203556c8a5ef82e99c4148ef1b9626d663fc8aabefee8eecbb016439d0dc255b6c01483045022100cc20e9db6c4ae335eb6a9af4f9f915b8dc9e6e130af4266a3c720464796d68b3022010203f84d6f9cc20fba81d2971fcb276595c6c5ed6f009f99da5cea93ff5dfdc01483045022100e39c1896c909b87f2d860ba23af7e94873dfeccee33657d28041335ca708bb36022002b70cb3050bf418645e4703958252706e3008ac7a940a7248747f5651b0ea0a01004dc801645521020ace50bab1230f8002a0bfe619482af74b338cc9e4c956add228df47e6adae1c210231a395e332dde8688800a0025cccc5771ea1aa874a633b8ab6e5c89d300c7c3621025093f439fb8006fd29ab56605ffec9cdc840d16d2361004e1337a2f86d8bd2db21026b472f7d59d201ff1f540f111b6eb329e071c30a9d23e3d2bcd128fe73dc254c2103250c11be0561b1d7ae168b1f59e39cbc1fd1ba3cf4d2140c1a365b2723a2bf93210357f7ed4c118e581f49cd3b4d9dd1edb4295f4def49d6dcf2faaaaac87a1a0a422103ae72827d25030818c4947a800187b1fbcc33ae751e248ae60094cc989fb880f62103e05bf6002b62651378b1954820539c36ca405cbb778c225395dd9ebff67802992103ecd8af1e93c57a1b8c7f917bd9980af798adeb0205e9687865673353eb041e8d59670350cd00b275532102370a9838e4d15708ad14a104ee5606b36caaaaf739d833e67770ce9fd9b3ec80210257c293086c4d4fe8943deda5f890a37d11bebd140e220faa76258a41d077b4d42103c2660a46aa73078ee6016dee953488566426cf55fc8011edd0085634d75395f92103cd3e383ec6e12719a6c69515e5559bcbe037d0aa24c187e1e26ce932e22ad7b35468aeffffffff026cd03c00000000001976a9143a267e4435e590d9e711d04954d8c8ef1003658588aca59f1d020000000017a91485aaffdabb34e8f7403291b3eff574129cc2486d8700000000").unwrap();
926 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
927 let in0 = &tx.input[0];
928 assert!(in0.is_p2sh().unwrap());
929 assert_eq!(in0.get_type().unwrap(), InputType::P2sh);
930 let in0_sigops = in0.sigops().unwrap();
931 assert_eq!(in0_sigops, 80);
932 }
933
934 #[test]
935 fn input_type_detection_nested_p2wsh() {
936 let rawtx = hex::decode("0100000000010158cffd9e03ff81e25367b93c78fe57c9a47dfd50e3365a0a210d7a75068333340100000023220020779b3b5851cbe7c95c7b21cd919aaf3df20b1f62f1dfc13bf93e734b3c88443ffdffffff01fca10000000000001976a914ea800dbd672b26181f9858bc0abedf40be747f3688ac0400483045022100d602eb075e28221a1b4622f24fa0a60242c90742033f032d40856ce0caed097c022061d066b92311b9492def6e0cc8bc0b76f73050b607a6d268f35d18d636ec7b940147304402203335fa91e31b8ec4e3ac5ddeb7fb2546c55a7aa6ee9548844337007dd29fcaac02204fbb78515a7085a9342c97c55b4f948681c3c1c80f9b2be5c9bd8e77a8cb6c240169522102a7b58e322616b2ac3752f59349b941edb5e9913f70864fc94a927b7592fe6d952103416995a2564b1fae34f521ad6745ffd04291bbda7075105e04720879ad728da52102523aa65c4a392a2ea8d81b8cd3bc19bba4b62a152f94a83f428c9b018dfc42d553ae00000000").unwrap();
938 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
939 let in0 = &tx.input[0];
940 assert!(in0.is_nested_p2wsh());
941 assert_eq!(in0.get_type().unwrap(), InputType::P2shP2wsh);
942 }
943
944 #[test]
945 fn input_type_detection_p2ms_1of2() {
946 let rawtx = hex::decode("01000000013de6aff69d5ebeca70a84d1dcef768bbcadbad210084012f8cda24233c8db278000000004b00493046022100a41a9015c847f404a14fcc81bf711ee2ce57583987948d54ebe540aafca97e0d022100d4e30d1ca42f77df8290b8975aa8fc0733d7c0cfdd5067ca516bac6c4012b47a01ffffffff01607d860500000000475121037953dbf08030f67352134992643d033417eaa6fcfb770c038f364ff40d7615882100dd28dfb81abe444429c466a1e3ab7c22365c48f234ef0f8d40397202969d4e9552ae00000000").unwrap();
948 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
949 let in0 = &tx.input[0];
950 assert!(in0.is_p2ms(true).unwrap());
951 assert_eq!(in0.get_type().unwrap(), InputType::P2ms);
952 assert_eq!(
953 in0.multisig_info().unwrap().unwrap(),
954 MultisigInputInfo {
955 m_of_n: (1, 0),
956 unknown_n: true
957 }
958 );
959 }
960
961 #[test]
962 fn input_type_detection_p2ms_2of3() {
963 let rawtx = hex::decode("010000000110a5fee9786a9d2d72c25525e52dd70cbd9035d5152fac83b62d3aa7e2301d58000000009300483045022100af204ef91b8dba5884df50f87219ccef22014c21dd05aa44470d4ed800b7f6e40220428fe058684db1bb2bfb6061bff67048592c574effc217f0d150daedcf36787601483045022100e8547aa2c2a2761a5a28806d3ae0d1bbf0aeff782f9081dfea67b86cacb321340220771a166929469c34959daf726a2ac0c253f9aff391e58a3c7cb46d8b7e0fdc4801ffffffff0180a21900000000001976a914971802edf585cdbc4e57017d6e5142515c1e502888ac00000000").unwrap();
965 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
966 let in0 = &tx.input[0];
967 assert!(in0.is_p2ms(true).unwrap());
968 assert_eq!(in0.get_type().unwrap(), InputType::P2ms);
969 assert_eq!(
970 in0.multisig_info().unwrap().unwrap(),
971 MultisigInputInfo {
972 m_of_n: (2, 0),
973 unknown_n: true
974 }
975 );
976 }
977
978 #[test]
979 fn input_type_detection_unknown() {
980 let rawtx = hex::decode("0100000003d4dfa41ffe9825af0aad023f084b4dd4a599d6cb8d083e58e3a53e8ad682a6ae010000000401030103ffffffffe2274e1294e1708f344e7cd5156648750bc60d3bf3705130cdcba66675e3439b010000000401030103fffffffff41d101368d124c5b10bf130bceece07623d87767a2c950a35d1b7b6217a2329000000000401030103ffffffff0170032d00000000001976a91429c9743283afd76eed5811788b20b23f9eece00788ac00000000").unwrap();
982 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
983 let in0 = &tx.input[0];
984 assert!(in0.is_p2sh().unwrap());
985 assert_eq!(in0.get_type().unwrap(), InputType::P2sh);
986 }
987
988 #[test]
989 fn input_type_detection_p2wsh_2of2() {
990 let rawtx = hex::decode("01000000000101ec2ad0604a0e708963a39d16936118ab5fb36dcb5d5e07f3dc2ca149412500eb0100000000ffffffff0233cc08000000000017a9147f152249241d7320a80a013fd46907c1a1eff5a4879a3a5c15000000002200202ceaf557137c8f1f8ac2c8ee4a6656f9533c250c62b40006956ecb44e5c2357e040047304402201489d616c691fb1a4dd86caa495991463d88e049fdc6e316bd09877cb4bc17de02201ebba0c182a6e28024944e63638788f44b77acbd85fbea60b1225f180def8fc901483045022100c00674b0810fe3e5db048bdd231f7a50edc1cc2ffd75a68497d43fae7853277802200a9422b26290b7521574a5c161e2116ef3e906030f6ed08ca38b6ee6c5690ddb0147522103a2ea7e0b94c48fd799bf123c1f19b50fb6d15da310db8223fd7a6afd8b03e6932102eba627e6ea5bb7e0f4c981596872d0a97d800fb836b5b3a585c3f2b99c77a0e552ae00000000").unwrap();
992 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
993 let in0 = &tx.input[0];
994 assert!(in0.is_p2wsh());
995 assert_eq!(in0.get_type().unwrap(), InputType::P2wsh);
996 assert_eq!(
997 in0.multisig_info().unwrap().unwrap(),
998 MultisigInputInfo {
999 m_of_n: (2, 2),
1000 unknown_n: false
1001 }
1002 );
1003 }
1004
1005 #[test]
1006 fn input_type_detection_p2wsh_non_multisig() {
1007 let rawtx = hex::decode("02000000000101d29021fae716cbc98333fa1a88fa2a5cf6fd2db642a94ff33d7dfff2ad361fc30100000000ffffffff01ffdc0b00000000001600142c3a8a495c16839d5d975c1ca0ee504af825b52105483045022100d45ed56c316849b6ff15a568608aa887be0f5a09ad89d76f686949f320509d5902204e61db9bf6bb965b2de1ee0bb6d687a28579b0f725bde9d0e6c9a1c0a8cb6a0f0121020251be8c4c748fce671be54e247534f34d4c1b7f7784e3fc08ef41b3805a4af820535692b33b9f226fd70cd5571c68df7bfa5463d4a334a5ceb4d200fd0663f06a0101636382012088a820697ce4e1d91cdc96d53d1bc591367bd48855a076301972842aa5ffcb8fcb8b618876a9142c3a8a495c16839d5d975c1ca0ee504af825b52188ac6704c9191960b17576a9145a59f40f4ecb1f86efb13752b600ea3b8d4c633988ac6800000000").unwrap();
1009 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1010 let in0 = &tx.input[0];
1011 assert!(in0.is_p2wsh());
1012 assert_eq!(in0.get_type().unwrap(), InputType::P2wsh);
1013 assert_eq!(in0.multisig_info().unwrap(), None);
1014 }
1015
1016 #[test]
1017 fn coinbase_input_detection() {
1018 let rawtx = hex::decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4803e09304062f503253482f0403c86d53087ceca141295a00002e522cfabe6d6d7561cf262313da1144026c8f7a43e3899c44f6145f39a36507d36679a8b7006104000000000000000000000001c8704095000000001976a91480ad90d403581fa3bf46086a91b2d9d4125db6c188ac00000000").unwrap();
1020 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1021 let in0 = &tx.input[0];
1022 assert!(in0.is_coinbase());
1023 assert_eq!(in0.get_type().unwrap(), InputType::Coinbase);
1024 }
1025
1026 #[test]
1027 fn coinbase_input_detection2() {
1028 let rawtx = hex::decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff11036e8405045583b024acec8dee00000efbffffffff01553d3b95000000001976a914ca6ecc7d4d671d8c5c964a48dbb0bc194407a30688ac00000000").unwrap();
1032 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1033 let in0 = &tx.input[0];
1034 assert!(in0.is_coinbase());
1035 assert_eq!(in0.get_type().unwrap(), InputType::Coinbase);
1036 }
1037
1038 #[test]
1039 fn p2trkp_input_detection() {
1040 let rawtx = hex::decode("0200000000010232b1c6063448c8089d4e7a500399555daec6bc1f3fef281016518c1de3d154cb0000000000feffffff32b1c6063448c8089d4e7a500399555daec6bc1f3fef281016518c1de3d154cb0100000000feffffff02301b0f00000000002251204b03959143386c56a1646c9d1002314c6acecd79ee0f0976fb9fa0f1f0837b1be31f0000000000001600140af8bb24c9504e8740076bb07b755237d4af6e67014159f6076cc04503a9bc72f137aa4af523ab05f5805b5fcb9e0b0b0f258a86afd30c7298e11203f6f27a1408385ec5b9fc1d16be738d628a4aac62eef1cfdac10b0102473044022044d39c6b67334c5e1aa0be056b2200221f8ec84e7319ba1b1cbe6df4dc2f6b1d02207289dd7e3d362355f22ff1df76965391ccd9c4d529a216947d2434f16dfd9b7901210338008b55bf51d06440c64129665a56c2eb828fdad50cca74191d29f92475e962b5680000").unwrap();
1042 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1043 let in0 = &tx.input[0];
1044 assert!(in0.is_p2trkp());
1045 assert_eq!(in0.get_type().unwrap(), InputType::P2trkp);
1046 assert!(InputInfo::new(in0).unwrap().is_spending_taproot());
1047 assert!(InputInfo::new(in0).unwrap().is_spending_segwit());
1048 }
1049
1050 #[test]
1051 fn p2trsp_input_detection() {
1052 let rawtx = hex::decode("02000000000101e1e91316b8780879bf5ac7559cbb3da5c65f19e57ed822615d832c53b2eeb5360000000000ffffffff01905f010000000000160014734e7298bfe985c5e0148a5a37179b66d9ad0b0804400d1e89bad817848056c3f32b4226f70946b84d358ff5a635b70f7ce40a43a94eba9b8ce213bc56d8ab6f9bb2f90d700cfed82fd93d91f41e7b3cf27c5b3ea77b20107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f45a8206c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd533388204edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10ac41c1f30544d6009c8d8d94f5d030b2e844b1a3ca036255161c479db1cca5b374dd1cc81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c900000000").unwrap();
1054 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1055 let in0 = &tx.input[0];
1056 assert!(in0.is_p2trsp());
1057 assert_eq!(in0.get_type().unwrap(), InputType::P2trsp);
1058 assert!(InputInfo::new(in0).unwrap().is_spending_taproot());
1059 assert!(InputInfo::new(in0).unwrap().is_spending_segwit());
1060 assert!(!in0.reveals_inscription().unwrap());
1061 }
1062
1063 #[test]
1064 fn p2a_input_detection() {
1065 let rawtx = hex::decode("020000000113c59a9590b576fbe82677888d9cea0639ffe077c6b42fb3599d3ad37cc6ef730000000000ffffffff010000000000000000056a032e2e2e00000000").unwrap();
1067 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1068 let in0 = &tx.input[0];
1069 assert!(in0.is_p2a());
1070 assert_eq!(in0.get_type().unwrap(), InputType::P2a);
1071 assert!(!InputInfo::new(in0).unwrap().is_spending_taproot());
1072 assert!(InputInfo::new(in0).unwrap().is_spending_segwit());
1073 assert!(!in0.reveals_inscription().unwrap());
1074 }
1075
1076 #[test]
1077 fn coinbase_witness_input_detection() {
1078 let rawtx = hex::decode("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff5b0314340a41d806348bf412e341d806348bafbbed2f45324d2026204254432e544f502ffabe6d6d2c7a0f4d5f67376109bb4e6e78904381170ee6ee0715344da30602c49d869cf68000000000000000e60086988fb8000000000000ffffffff023e740b2c000000001976a9140b904a4a8590d0ccff680bb8adc4ae4fe49f890a88ac0000000000000000266a24aa21a9ed165dbbf9c556629ce3b8f2e748f7ca8372131ca6cf47e95736efd8f73dcea77d0120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
1080 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1081 let in0 = &tx.input[0];
1082 assert!(in0.is_coinbase_witness());
1083 assert_eq!(in0.get_type().unwrap(), InputType::CoinbaseWitness);
1084 }
1085
1086 #[test]
1087 fn non_der_sig_p2pkh_input_detection() {
1088 let rawtx = hex::decode("01000000012316aac445c13ff31af5f3d1e2cebcada83e54ba10d15e01f49ec28bddc285aa000000008e4b3048022200002b83d59c1d23c08efd82ee0662fec23309c3adbcbd1f0b8695378db4b14e736602220000334a96676e58b1bb01784cb7c556dd8ce1c220171904da22e18fe1e7d1510db5014104d0fe07ff74c9ef5b00fed1104fad43ecf72dbab9e60733e4f56eacf24b20cf3b8cd945bcabcc73ba0158bf9ce769d43e94bd58c5c7e331a188922b3fe9ca1f5affffffff01c0c62d00000000001976a9147a2a3b481ca80c4ba7939c54d9278e50189d94f988ac00000000").unwrap();
1090 let tx: Transaction = bitcoin::consensus::deserialize(&rawtx).unwrap();
1091 let in0 = &tx.input[0];
1092 assert!(in0.is_p2pkh(false).unwrap());
1093 assert_eq!(in0.get_type().unwrap(), InputType::P2pkhLaxDer);
1094 }
1095}