|
|
@ -243,6 +243,11 @@ class TxInput: |
|
|
|
n = vds.read_compact_size() |
|
|
|
return list(vds.read_bytes(vds.read_compact_size()) for i in range(n)) |
|
|
|
|
|
|
|
def is_segwit(self, *, guess_for_address=False) -> bool: |
|
|
|
if self.witness not in (b'\x00', b'', None): |
|
|
|
return True |
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
class BCDataStream(object): |
|
|
|
"""Workalike python implementation of Bitcoin's CDataStream class.""" |
|
|
@ -635,7 +640,7 @@ class Transaction: |
|
|
|
assert isinstance(txin, PartialTxInput) |
|
|
|
|
|
|
|
_type = txin.script_type |
|
|
|
if not cls.is_segwit_input(txin): |
|
|
|
if not txin.is_segwit(): |
|
|
|
return construct_witness([]) |
|
|
|
|
|
|
|
if _type in ('address', 'unknown') and estimate_size: |
|
|
@ -650,23 +655,6 @@ class Transaction: |
|
|
|
return construct_witness([]) |
|
|
|
raise UnknownTxinType(f'cannot construct witness for txin_type: {_type}') |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def is_segwit_input(cls, txin: 'TxInput', *, guess_for_address=False) -> bool: |
|
|
|
if txin.witness not in (b'\x00', b'', None): |
|
|
|
return True |
|
|
|
if not isinstance(txin, PartialTxInput): |
|
|
|
return False |
|
|
|
if txin.is_native_segwit() or txin.is_p2sh_segwit(): |
|
|
|
return True |
|
|
|
if txin.is_native_segwit() is False and txin.is_p2sh_segwit() is False: |
|
|
|
return False |
|
|
|
if txin.witness_script: |
|
|
|
return True |
|
|
|
_type = txin.script_type |
|
|
|
if _type == 'address' and guess_for_address: |
|
|
|
_type = cls.guess_txintype_from_address(txin.address) |
|
|
|
return is_segwit_script_type(_type) |
|
|
|
|
|
|
|
@classmethod |
|
|
|
def guess_txintype_from_address(cls, addr: Optional[str]) -> str: |
|
|
|
# It's not possible to tell the script type in general |
|
|
@ -771,7 +759,7 @@ class Transaction: |
|
|
|
hashOutputs=hashOutputs) |
|
|
|
|
|
|
|
def is_segwit(self, *, guess_for_address=False): |
|
|
|
return any(self.is_segwit_input(txin, guess_for_address=guess_for_address) |
|
|
|
return any(txin.is_segwit(guess_for_address=guess_for_address) |
|
|
|
for txin in self.inputs()) |
|
|
|
|
|
|
|
def invalidate_ser_cache(self): |
|
|
@ -829,7 +817,7 @@ class Transaction: |
|
|
|
def txid(self) -> Optional[str]: |
|
|
|
if self._cached_txid is None: |
|
|
|
self.deserialize() |
|
|
|
all_segwit = all(self.is_segwit_input(x) for x in self.inputs()) |
|
|
|
all_segwit = all(txin.is_segwit() for txin in self.inputs()) |
|
|
|
if not all_segwit and not self.is_complete(): |
|
|
|
return None |
|
|
|
try: |
|
|
@ -873,7 +861,7 @@ class Transaction: |
|
|
|
script = cls.input_script(txin, estimate_size=True) |
|
|
|
input_size = len(cls.serialize_input(txin, script)) // 2 |
|
|
|
|
|
|
|
if cls.is_segwit_input(txin, guess_for_address=True): |
|
|
|
if txin.is_segwit(guess_for_address=True): |
|
|
|
witness_size = len(cls.serialize_witness(txin, estimate_size=True)) // 2 |
|
|
|
else: |
|
|
|
witness_size = 1 if is_segwit_tx else 0 |
|
|
@ -1200,7 +1188,7 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
# without verifying the input amount. This means, given a maliciously modified PSBT, |
|
|
|
# for non-segwit inputs, we might end up burning coins as miner fees. |
|
|
|
if for_signing and False: |
|
|
|
if not Transaction.is_segwit_input(self) and self.witness_utxo: |
|
|
|
if not self.is_segwit() and self.witness_utxo: |
|
|
|
raise PSBTInputConsistencyFailure(f"PSBT input validation: " |
|
|
|
f"If a witness UTXO is provided, no non-witness signature may be created") |
|
|
|
if self.redeem_script and self.address: |
|
|
@ -1340,7 +1328,7 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
return True |
|
|
|
if self.is_coinbase_input(): |
|
|
|
return True |
|
|
|
if self.script_sig is not None and not Transaction.is_segwit_input(self): |
|
|
|
if self.script_sig is not None and not self.is_segwit(): |
|
|
|
return True |
|
|
|
signatures = list(self.part_sigs.values()) |
|
|
|
s = len(signatures) |
|
|
@ -1442,6 +1430,20 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
self._is_p2sh_segwit = calc_if_p2sh_segwit_now() |
|
|
|
return self._is_p2sh_segwit |
|
|
|
|
|
|
|
def is_segwit(self, *, guess_for_address=False) -> bool: |
|
|
|
if super().is_segwit(): |
|
|
|
return True |
|
|
|
if self.is_native_segwit() or self.is_p2sh_segwit(): |
|
|
|
return True |
|
|
|
if self.is_native_segwit() is False and self.is_p2sh_segwit() is False: |
|
|
|
return False |
|
|
|
if self.witness_script: |
|
|
|
return True |
|
|
|
_type = self.script_type |
|
|
|
if _type == 'address' and guess_for_address: |
|
|
|
_type = Transaction.guess_txintype_from_address(self.address) |
|
|
|
return is_segwit_script_type(_type) |
|
|
|
|
|
|
|
def already_has_some_signatures(self) -> bool: |
|
|
|
"""Returns whether progress has been made towards completing this input.""" |
|
|
|
return (self.part_sigs |
|
|
@ -1790,7 +1792,7 @@ class PartialTransaction(Transaction): |
|
|
|
raise Exception("only SIGHASH_ALL signing is supported!") |
|
|
|
nHashType = int_to_hex(sighash, 4) |
|
|
|
preimage_script = self.get_preimage_script(txin) |
|
|
|
if self.is_segwit_input(txin): |
|
|
|
if txin.is_segwit(): |
|
|
|
if bip143_shared_txdigest_fields is None: |
|
|
|
bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields() |
|
|
|
hashPrevouts = bip143_shared_txdigest_fields.hashPrevouts |
|
|
|