Fix errors caused by P2TR inputs without witness data
This commit is contained in:
		
							parent
							
								
									98e9d1a6c3
								
							
						
					
					
						commit
						7432e6e29b
					
				| @ -71,19 +71,24 @@ export function calcSegwitFeeGains(tx: Transaction) { | ||||
|     } | ||||
| 
 | ||||
|     if (isP2tr) { | ||||
|       if (vin.witness.length === 1) { | ||||
|         // key path spend
 | ||||
|         // we don't know if this was a multisig or single sig (the goal of taproot :)),
 | ||||
|         // so calculate fee savings by comparing to the cheapest single sig input type: P2WPKH and say "saved at least ...%"
 | ||||
|         // the witness size of P2WPKH is 1 (stack size) + 1 (size) + 72 (low s signature) + 1 (size) + 33 (pubkey) = 108 WU
 | ||||
|         // the witness size of key path P2TR is 1 (stack size) + 1 (size) + 64 (signature) = 66 WU
 | ||||
|         realizedTaprootGains += 42; | ||||
|       } else { | ||||
|         // script path spend
 | ||||
|         // complex scripts with multiple spending paths can often be made around 2x to 3x smaller with the Taproot script tree
 | ||||
|         // because only the hash of the alternative spending path has the be in the witness data, not the entire script,
 | ||||
|         // but only assumptions can be made because the scripts themselves are unknown (again, the goal of taproot :))
 | ||||
|         // TODO maybe add some complex scripts that are specified somewhere, so that size is known, such as lightning scripts
 | ||||
|       // every valid taproot input has at least one witness item, however transactions
 | ||||
|       // created before taproot activation don't need to have any witness data
 | ||||
|       // (see https://mempool.space/tx/b10c007c60e14f9d087e0291d4d0c7869697c6681d979c6639dbd960792b4d41)
 | ||||
|       if (vin.witness?.length) { | ||||
|         if (vin.witness.length === 1) { | ||||
|           // key path spend
 | ||||
|           // we don't know if this was a multisig or single sig (the goal of taproot :)),
 | ||||
|           // so calculate fee savings by comparing to the cheapest single sig input type: P2WPKH and say "saved at least ...%"
 | ||||
|           // the witness size of P2WPKH is 1 (stack size) + 1 (size) + 72 (low s signature) + 1 (size) + 33 (pubkey) = 108 WU
 | ||||
|           // the witness size of key path P2TR is 1 (stack size) + 1 (size) + 64 (signature) = 66 WU
 | ||||
|           realizedTaprootGains += 42; | ||||
|         } else { | ||||
|           // script path spend
 | ||||
|           // complex scripts with multiple spending paths can often be made around 2x to 3x smaller with the Taproot script tree
 | ||||
|           // because only the hash of the alternative spending path has the be in the witness data, not the entire script,
 | ||||
|           // but only assumptions can be made because the scripts themselves are unknown (again, the goal of taproot :))
 | ||||
|           // TODO maybe add some complex scripts that are specified somewhere, so that size is known, such as lightning scripts
 | ||||
|         } | ||||
|       } | ||||
|     } else { | ||||
|       const script = isP2shP2Wsh || isP2wsh ? vin.inner_witnessscript_asm : vin.inner_redeemscript_asm; | ||||
|  | ||||
| @ -335,19 +335,21 @@ export function getTransactionFlags(tx: Transaction, cpfpInfo?: CpfpInfo, replac | ||||
|       case 'v0_p2wpkh': flags |= TransactionFlags.p2wpkh; break; | ||||
|       case 'v0_p2wsh': flags |= TransactionFlags.p2wsh; break; | ||||
|       case 'v1_p2tr': { | ||||
|         if (!vin.witness?.length) { | ||||
|           throw new Error('Taproot input missing witness data'); | ||||
|         } | ||||
|         flags |= TransactionFlags.p2tr; | ||||
|         // in taproot, if the last witness item begins with 0x50, it's an annex
 | ||||
|         const hasAnnex = vin.witness?.[vin.witness.length - 1].startsWith('50'); | ||||
|         // script spends have more than one witness item, not counting the annex (if present)
 | ||||
|         if (vin.witness.length > (hasAnnex ? 2 : 1)) { | ||||
|           // the script itself is the second-to-last witness item, not counting the annex
 | ||||
|           const asm = vin.inner_witnessscript_asm; | ||||
|           // inscriptions smuggle data within an 'OP_0 OP_IF ... OP_ENDIF' envelope
 | ||||
|           if (asm?.includes('OP_0 OP_IF')) { | ||||
|             flags |= TransactionFlags.inscription; | ||||
|         // every valid taproot input has at least one witness item, however transactions
 | ||||
|         // created before taproot activation don't need to have any witness data
 | ||||
|         // (see https://mempool.space/tx/b10c007c60e14f9d087e0291d4d0c7869697c6681d979c6639dbd960792b4d41)
 | ||||
|         if (vin.witness?.length) { | ||||
|           // in taproot, if the last witness item begins with 0x50, it's an annex
 | ||||
|           const hasAnnex = vin.witness?.[vin.witness.length - 1].startsWith('50'); | ||||
|           // script spends have more than one witness item, not counting the annex (if present)
 | ||||
|           if (vin.witness.length > (hasAnnex ? 2 : 1)) { | ||||
|             // the script itself is the second-to-last witness item, not counting the annex
 | ||||
|             const asm = vin.inner_witnessscript_asm; | ||||
|             // inscriptions smuggle data within an 'OP_0 OP_IF ... OP_ENDIF' envelope
 | ||||
|             if (asm?.includes('OP_0 OP_IF')) { | ||||
|               flags |= TransactionFlags.inscription; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } break; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user