|
|
@ -1126,8 +1126,8 @@ class PSBTSection: |
|
|
|
class PartialTxInput(TxInput, PSBTSection): |
|
|
|
def __init__(self, *args, **kwargs): |
|
|
|
TxInput.__init__(self, *args, **kwargs) |
|
|
|
self.utxo = None # type: Optional[Transaction] |
|
|
|
self.witness_utxo = None # type: Optional[TxOutput] |
|
|
|
self._utxo = None # type: Optional[Transaction] |
|
|
|
self._witness_utxo = None # type: Optional[TxOutput] |
|
|
|
self.part_sigs = {} # type: Dict[bytes, bytes] # pubkey -> sig |
|
|
|
self.sighash = None # type: Optional[int] |
|
|
|
self.bip32_paths = {} # type: Dict[bytes, Tuple[bytes, Sequence[int]]] # pubkey -> (xpub_fingerprint, path) |
|
|
@ -1145,6 +1145,26 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
self._is_p2sh_segwit = None # type: Optional[bool] # None means unknown |
|
|
|
self._is_native_segwit = None # type: Optional[bool] # None means unknown |
|
|
|
|
|
|
|
@property |
|
|
|
def utxo(self): |
|
|
|
return self._utxo |
|
|
|
|
|
|
|
@utxo.setter |
|
|
|
def utxo(self, value: Optional[Transaction]): |
|
|
|
self._utxo = value |
|
|
|
self.validate_data() |
|
|
|
self.ensure_there_is_only_one_utxo() |
|
|
|
|
|
|
|
@property |
|
|
|
def witness_utxo(self): |
|
|
|
return self._witness_utxo |
|
|
|
|
|
|
|
@witness_utxo.setter |
|
|
|
def witness_utxo(self, value: Optional[TxOutput]): |
|
|
|
self._witness_utxo = value |
|
|
|
self.validate_data() |
|
|
|
self.ensure_there_is_only_one_utxo() |
|
|
|
|
|
|
|
def to_json(self): |
|
|
|
d = super().to_json() |
|
|
|
d.update({ |
|
|
@ -1177,6 +1197,10 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
if self.prevout.txid.hex() != self.utxo.txid(): |
|
|
|
raise PSBTInputConsistencyFailure(f"PSBT input validation: " |
|
|
|
f"If a non-witness UTXO is provided, its hash must match the hash specified in the prevout") |
|
|
|
if self.witness_utxo: |
|
|
|
if self.utxo.outputs()[self.prevout.out_idx] != self.witness_utxo: |
|
|
|
raise PSBTInputConsistencyFailure(f"PSBT input validation: " |
|
|
|
f"If both non-witness UTXO and witness UTXO are provided, they must be consistent") |
|
|
|
# The following test is disabled, so we are willing to sign non-segwit inputs |
|
|
|
# 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. |
|
|
@ -1208,16 +1232,12 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
if kt == PSBTInputType.NON_WITNESS_UTXO: |
|
|
|
if self.utxo is not None: |
|
|
|
raise SerializationError(f"duplicate key: {repr(kt)}") |
|
|
|
if self.witness_utxo is not None: |
|
|
|
raise SerializationError(f"PSBT input cannot have both PSBT_IN_NON_WITNESS_UTXO and PSBT_IN_WITNESS_UTXO") |
|
|
|
self.utxo = Transaction(val) |
|
|
|
self.utxo.deserialize() |
|
|
|
if key: raise SerializationError(f"key for {repr(kt)} must be empty") |
|
|
|
elif kt == PSBTInputType.WITNESS_UTXO: |
|
|
|
if self.witness_utxo is not None: |
|
|
|
raise SerializationError(f"duplicate key: {repr(kt)}") |
|
|
|
if self.utxo is not None: |
|
|
|
raise SerializationError(f"PSBT input cannot have both PSBT_IN_NON_WITNESS_UTXO and PSBT_IN_WITNESS_UTXO") |
|
|
|
self.witness_utxo = TxOutput.from_network_bytes(val) |
|
|
|
if key: raise SerializationError(f"key for {repr(kt)} must be empty") |
|
|
|
elif kt == PSBTInputType.PARTIAL_SIG: |
|
|
@ -1266,9 +1286,10 @@ class PartialTxInput(TxInput, PSBTSection): |
|
|
|
self._unknown[full_key] = val |
|
|
|
|
|
|
|
def serialize_psbt_section_kvs(self, wr): |
|
|
|
self.ensure_there_is_only_one_utxo() |
|
|
|
if self.witness_utxo: |
|
|
|
wr(PSBTInputType.WITNESS_UTXO, self.witness_utxo.serialize_to_network()) |
|
|
|
elif self.utxo: |
|
|
|
if self.utxo: |
|
|
|
wr(PSBTInputType.NON_WITNESS_UTXO, bfh(self.utxo.serialize_to_network(include_sigs=True))) |
|
|
|
for pk, val in sorted(self.part_sigs.items()): |
|
|
|
wr(PSBTInputType.PARTIAL_SIG, val, pk) |
|
|
|