|
@ -86,6 +86,12 @@ class TxOutputHwInfo(NamedTuple): |
|
|
script_type: str |
|
|
script_type: str |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BIP143SharedTxDigestFields(NamedTuple): |
|
|
|
|
|
hashPrevouts: str |
|
|
|
|
|
hashSequence: str |
|
|
|
|
|
hashOutputs: str |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BCDataStream(object): |
|
|
class BCDataStream(object): |
|
|
"""Workalike python implementation of Bitcoin's CDataStream class.""" |
|
|
"""Workalike python implementation of Bitcoin's CDataStream class.""" |
|
|
|
|
|
|
|
@ -958,7 +964,18 @@ class Transaction: |
|
|
s += script |
|
|
s += script |
|
|
return s |
|
|
return s |
|
|
|
|
|
|
|
|
def serialize_preimage(self, txin_index: int) -> str: |
|
|
def _calc_bip143_shared_txdigest_fields(self) -> BIP143SharedTxDigestFields: |
|
|
|
|
|
inputs = self.inputs() |
|
|
|
|
|
outputs = self.outputs() |
|
|
|
|
|
hashPrevouts = bh2u(sha256d(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs)))) |
|
|
|
|
|
hashSequence = bh2u(sha256d(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs)))) |
|
|
|
|
|
hashOutputs = bh2u(sha256d(bfh(''.join(self.serialize_output(o) for o in outputs)))) |
|
|
|
|
|
return BIP143SharedTxDigestFields(hashPrevouts=hashPrevouts, |
|
|
|
|
|
hashSequence=hashSequence, |
|
|
|
|
|
hashOutputs=hashOutputs) |
|
|
|
|
|
|
|
|
|
|
|
def serialize_preimage(self, txin_index: int, *, |
|
|
|
|
|
bip143_shared_txdigest_fields: BIP143SharedTxDigestFields = None) -> str: |
|
|
nVersion = int_to_hex(self.version, 4) |
|
|
nVersion = int_to_hex(self.version, 4) |
|
|
nHashType = int_to_hex(1, 4) # SIGHASH_ALL |
|
|
nHashType = int_to_hex(1, 4) # SIGHASH_ALL |
|
|
nLocktime = int_to_hex(self.locktime, 4) |
|
|
nLocktime = int_to_hex(self.locktime, 4) |
|
@ -966,9 +983,11 @@ class Transaction: |
|
|
outputs = self.outputs() |
|
|
outputs = self.outputs() |
|
|
txin = inputs[txin_index] |
|
|
txin = inputs[txin_index] |
|
|
if self.is_segwit_input(txin): |
|
|
if self.is_segwit_input(txin): |
|
|
hashPrevouts = bh2u(sha256d(bfh(''.join(self.serialize_outpoint(txin) for txin in inputs)))) |
|
|
if bip143_shared_txdigest_fields is None: |
|
|
hashSequence = bh2u(sha256d(bfh(''.join(int_to_hex(txin.get('sequence', 0xffffffff - 1), 4) for txin in inputs)))) |
|
|
bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields() |
|
|
hashOutputs = bh2u(sha256d(bfh(''.join(self.serialize_output(o) for o in outputs)))) |
|
|
hashPrevouts = bip143_shared_txdigest_fields.hashPrevouts |
|
|
|
|
|
hashSequence = bip143_shared_txdigest_fields.hashSequence |
|
|
|
|
|
hashOutputs = bip143_shared_txdigest_fields.hashOutputs |
|
|
outpoint = self.serialize_outpoint(txin) |
|
|
outpoint = self.serialize_outpoint(txin) |
|
|
preimage_script = self.get_preimage_script(txin) |
|
|
preimage_script = self.get_preimage_script(txin) |
|
|
scriptCode = var_int(len(preimage_script) // 2) + preimage_script |
|
|
scriptCode = var_int(len(preimage_script) // 2) + preimage_script |
|
@ -1129,6 +1148,7 @@ class Transaction: |
|
|
|
|
|
|
|
|
def sign(self, keypairs) -> None: |
|
|
def sign(self, keypairs) -> None: |
|
|
# keypairs: (x_)pubkey -> secret_bytes |
|
|
# keypairs: (x_)pubkey -> secret_bytes |
|
|
|
|
|
bip143_shared_txdigest_fields = self._calc_bip143_shared_txdigest_fields() |
|
|
for i, txin in enumerate(self.inputs()): |
|
|
for i, txin in enumerate(self.inputs()): |
|
|
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) |
|
|
pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin) |
|
|
for j, (pubkey, x_pubkey) in enumerate(zip(pubkeys, x_pubkeys)): |
|
|
for j, (pubkey, x_pubkey) in enumerate(zip(pubkeys, x_pubkeys)): |
|
@ -1142,14 +1162,15 @@ class Transaction: |
|
|
continue |
|
|
continue |
|
|
_logger.info(f"adding signature for {_pubkey}") |
|
|
_logger.info(f"adding signature for {_pubkey}") |
|
|
sec, compressed = keypairs.get(_pubkey) |
|
|
sec, compressed = keypairs.get(_pubkey) |
|
|
sig = self.sign_txin(i, sec) |
|
|
sig = self.sign_txin(i, sec, bip143_shared_txdigest_fields=bip143_shared_txdigest_fields) |
|
|
self.add_signature_to_txin(i, j, sig) |
|
|
self.add_signature_to_txin(i, j, sig) |
|
|
|
|
|
|
|
|
_logger.info(f"is_complete {self.is_complete()}") |
|
|
_logger.info(f"is_complete {self.is_complete()}") |
|
|
self.raw = self.serialize() |
|
|
self.raw = self.serialize() |
|
|
|
|
|
|
|
|
def sign_txin(self, txin_index, privkey_bytes) -> str: |
|
|
def sign_txin(self, txin_index, privkey_bytes, *, bip143_shared_txdigest_fields=None) -> str: |
|
|
pre_hash = sha256d(bfh(self.serialize_preimage(txin_index))) |
|
|
pre_hash = sha256d(bfh(self.serialize_preimage(txin_index, |
|
|
|
|
|
bip143_shared_txdigest_fields=bip143_shared_txdigest_fields))) |
|
|
privkey = ecc.ECPrivkey(privkey_bytes) |
|
|
privkey = ecc.ECPrivkey(privkey_bytes) |
|
|
sig = privkey.sign_transaction(pre_hash) |
|
|
sig = privkey.sign_transaction(pre_hash) |
|
|
sig = bh2u(sig) + '01' |
|
|
sig = bh2u(sig) + '01' |
|
|