Browse Source

transaction: change Transaction.is_segwit_input(txin) to txin.is_segwit()

patch-4
SomberNight 5 years ago
parent
commit
eefb68c82b
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/coinchooser.py
  2. 2
      electrum/plugins/keepkey/keepkey.py
  3. 2
      electrum/plugins/ledger/ledger.py
  4. 2
      electrum/plugins/safe_t/safe_t.py
  5. 50
      electrum/transaction.py
  6. 4
      electrum/wallet.py

2
electrum/coinchooser.py

@ -120,7 +120,7 @@ class CoinChooserBase(Logger):
constant_fee = fee_estimator_vb(2000) == fee_estimator_vb(200)
def make_Bucket(desc: str, coins: List[PartialTxInput]):
witness = any(Transaction.is_segwit_input(coin, guess_for_address=True) for coin in coins)
witness = any(coin.is_segwit(guess_for_address=True) for coin in coins)
# note that we're guessing whether the tx uses segwit based
# on this single bucket
weight = sum(Transaction.estimated_input_weight(coin, witness)

2
electrum/plugins/keepkey/keepkey.py

@ -53,7 +53,7 @@ class KeepKey_KeyStore(Hardware_KeyStore):
prev_tx = {}
for txin in tx.inputs():
tx_hash = txin.prevout.txid.hex()
if txin.utxo is None and not Transaction.is_segwit_input(txin):
if txin.utxo is None and not txin.is_segwit():
raise UserFacingException(_('Missing previous tx for legacy input.'))
prev_tx[tx_hash] = txin.utxo

2
electrum/plugins/ledger/ledger.py

@ -384,7 +384,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
redeemScript = Transaction.get_preimage_script(txin)
txin_prev_tx = txin.utxo
if txin_prev_tx is None and not Transaction.is_segwit_input(txin):
if txin_prev_tx is None and not txin.is_segwit():
raise UserFacingException(_('Missing previous tx for legacy input.'))
txin_prev_tx_raw = txin_prev_tx.serialize() if txin_prev_tx else None
inputs.append([txin_prev_tx_raw,

2
electrum/plugins/safe_t/safe_t.py

@ -51,7 +51,7 @@ class SafeTKeyStore(Hardware_KeyStore):
prev_tx = {}
for txin in tx.inputs():
tx_hash = txin.prevout.txid.hex()
if txin.utxo is None and not Transaction.is_segwit_input(txin):
if txin.utxo is None and not txin.is_segwit():
raise UserFacingException(_('Missing previous tx for legacy input.'))
prev_tx[tx_hash] = txin.utxo

50
electrum/transaction.py

@ -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

4
electrum/wallet.py

@ -2162,7 +2162,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
if all([txin.utxo for txin in tx.inputs()]):
return None
# a single segwit input -> fine
if len(tx.inputs()) == 1 and Transaction.is_segwit_input(tx.inputs()[0]) and tx.inputs()[0].witness_utxo:
if len(tx.inputs()) == 1 and tx.inputs()[0].is_segwit() and tx.inputs()[0].witness_utxo:
return None
# coinjoin or similar
if any([not self.is_mine(txin.address) for txin in tx.inputs()]):
@ -2170,7 +2170,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
+ _("The input amounts could not be verified as the previous transactions are missing.\n"
"The amount of money being spent CANNOT be verified."))
# some inputs are legacy
if any([not Transaction.is_segwit_input(txin) for txin in tx.inputs()]):
if any([not txin.is_segwit() for txin in tx.inputs()]):
return (_("Warning") + ": "
+ _("The fee could not be verified. Signing non-segwit inputs is risky:\n"
"if this transaction was maliciously modified before you sign,\n"

Loading…
Cancel
Save