mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-28 07:51:27 +00:00
transaction.py: shortcut witness/scriptSig serialisation
This commit is contained in:
parent
b3110b3b46
commit
1d6f000868
4 changed files with 51 additions and 28 deletions
|
@ -188,6 +188,13 @@ def var_int(i):
|
|||
return "ff"+int_to_hex(i,8)
|
||||
|
||||
|
||||
def witness_push(item):
|
||||
""" Returns data in the form it should be present in the witness.
|
||||
hex -> hex
|
||||
"""
|
||||
return var_int(len(item) // 2) + item
|
||||
|
||||
|
||||
def op_push(i):
|
||||
if i<0x4c: # OP_PUSHDATA1
|
||||
return int_to_hex(i)
|
||||
|
|
|
@ -359,8 +359,9 @@ def parse_scriptSig(d, _bytes):
|
|||
match = [ opcodes.OP_0 ] + [ opcodes.OP_PUSHDATA4 ] * (len(decoded) - 1)
|
||||
if match_decoded(decoded, match):
|
||||
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
||||
redeem_script = bh2u(decoded[-1][1])
|
||||
try:
|
||||
m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1])
|
||||
m, n, x_pubkeys, pubkeys = parse_redeemScript_multisig(bfh(redeem_script))
|
||||
except NotRecognizedRedeemScript:
|
||||
print_error("parse_scriptSig: cannot find address in input script (p2sh?)",
|
||||
bh2u(_bytes))
|
||||
|
@ -373,16 +374,16 @@ def parse_scriptSig(d, _bytes):
|
|||
d['signatures'] = parse_sig(x_sig)
|
||||
d['x_pubkeys'] = x_pubkeys
|
||||
d['pubkeys'] = pubkeys
|
||||
d['redeemScript'] = redeemScript
|
||||
d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
|
||||
d['redeem_script'] = redeem_script
|
||||
d['address'] = hash160_to_p2sh(hash_160(bfh(redeem_script)))
|
||||
return
|
||||
|
||||
print_error("parse_scriptSig: cannot find address in input script (unknown)",
|
||||
bh2u(_bytes))
|
||||
|
||||
|
||||
def parse_redeemScript(s):
|
||||
dec2 = [ x for x in script_GetOp(s) ]
|
||||
def parse_redeemScript_multisig(redeem_script):
|
||||
dec2 = [ x for x in script_GetOp(redeem_script) ]
|
||||
try:
|
||||
m = dec2[0][0] - opcodes.OP_1 + 1
|
||||
n = dec2[-2][0] - opcodes.OP_1 + 1
|
||||
|
@ -395,8 +396,10 @@ def parse_redeemScript(s):
|
|||
raise NotRecognizedRedeemScript()
|
||||
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
||||
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
||||
redeemScript = multisig_script(pubkeys, m)
|
||||
return m, n, x_pubkeys, pubkeys, redeemScript
|
||||
redeem_script2 = bfh(multisig_script(pubkeys, m))
|
||||
if redeem_script2 != redeem_script:
|
||||
raise NotRecognizedRedeemScript()
|
||||
return m, n, x_pubkeys, pubkeys
|
||||
|
||||
|
||||
def get_address_from_output_script(_bytes, *, net=None):
|
||||
|
@ -471,8 +474,7 @@ def parse_witness(vds, txin):
|
|||
# now 'n' is the number of items in the witness
|
||||
w = list(bh2u(vds.read_bytes(vds.read_compact_size())) for i in range(n))
|
||||
|
||||
add_w = lambda x: var_int(len(x) // 2) + x
|
||||
txin['witness'] = var_int(n) + ''.join(add_w(i) for i in w)
|
||||
txin['witness'] = var_int(n) + ''.join(witness_push(i) for i in w)
|
||||
|
||||
# FIXME: witness version > 0 will probably fail here.
|
||||
# For native segwit, we would need the scriptPubKey of the parent txn
|
||||
|
@ -487,18 +489,19 @@ def parse_witness(vds, txin):
|
|||
if txin['type'] == 'coinbase':
|
||||
pass
|
||||
elif txin['type'] == 'p2wsh-p2sh' or n > 2:
|
||||
witness_script = w[-1]
|
||||
try:
|
||||
m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1]))
|
||||
m, n, x_pubkeys, pubkeys = parse_redeemScript_multisig(bfh(witness_script))
|
||||
except NotRecognizedRedeemScript:
|
||||
raise UnknownTxinType()
|
||||
txin['signatures'] = parse_sig(w[1:-1])
|
||||
txin['num_sig'] = m
|
||||
txin['x_pubkeys'] = x_pubkeys
|
||||
txin['pubkeys'] = pubkeys
|
||||
txin['witnessScript'] = witnessScript
|
||||
txin['witness_script'] = witness_script
|
||||
if not txin.get('scriptSig'): # native segwit script
|
||||
txin['type'] = 'p2wsh'
|
||||
txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript'])
|
||||
txin['address'] = bitcoin.script_to_p2wsh(witness_script)
|
||||
elif txin['type'] == 'p2wpkh-p2sh' or n == 2:
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [w[1]]
|
||||
|
@ -641,12 +644,18 @@ class Transaction:
|
|||
public_key.verify_digest(sig_string, pre_hash, sigdecode = ecdsa.util.sigdecode_string)
|
||||
j = pubkeys.index(pubkey)
|
||||
print_error("adding sig", i, j, pubkey, sig)
|
||||
self._inputs[i]['signatures'][j] = sig
|
||||
self.add_signature_to_txin(self._inputs[i], j, sig)
|
||||
#self._inputs[i]['x_pubkeys'][j] = pubkey
|
||||
break
|
||||
# redo raw
|
||||
self.raw = self.serialize()
|
||||
|
||||
@classmethod
|
||||
def add_signature_to_txin(cls, txin, signingPos, sig):
|
||||
txin['signatures'][signingPos] = sig
|
||||
txin['scriptSig'] = None # force re-serialization
|
||||
txin['witness'] = None # force re-serialization
|
||||
|
||||
def deserialize(self):
|
||||
if self.raw is None:
|
||||
return
|
||||
|
@ -736,17 +745,17 @@ class Transaction:
|
|||
return '00'
|
||||
if txin['type'] == 'coinbase':
|
||||
return txin['witness']
|
||||
pubkeys, sig_list = self.get_siglist(txin, estimate_size)
|
||||
add_w = lambda x: var_int(len(x) // 2) + x
|
||||
if txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||
witness = var_int(2) + add_w(sig_list[0]) + add_w(pubkeys[0])
|
||||
elif txin['type'] in ['p2wsh', 'p2wsh-p2sh']:
|
||||
n = len(sig_list) + 2
|
||||
witness_script = multisig_script(pubkeys, txin['num_sig'])
|
||||
witness = var_int(n) + '00' + ''.join(add_w(x) for x in sig_list) + add_w(witness_script)
|
||||
else:
|
||||
witness = txin.get('witness', None)
|
||||
if not witness:
|
||||
|
||||
witness = txin.get('witness', None)
|
||||
if witness is None:
|
||||
pubkeys, sig_list = self.get_siglist(txin, estimate_size)
|
||||
if txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
|
||||
witness = var_int(2) + witness_push(sig_list[0]) + witness_push(pubkeys[0])
|
||||
elif txin['type'] in ['p2wsh', 'p2wsh-p2sh']:
|
||||
n = len(sig_list) + 2
|
||||
witness_script = multisig_script(pubkeys, txin['num_sig'])
|
||||
witness = var_int(n) + '00' + ''.join(witness_push(x) for x in sig_list) + witness_push(witness_script)
|
||||
else:
|
||||
raise Exception('wrong txin type:', txin['type'])
|
||||
if self.is_txin_complete(txin) or estimate_size:
|
||||
value_field = ''
|
||||
|
@ -756,7 +765,7 @@ class Transaction:
|
|||
|
||||
@classmethod
|
||||
def is_segwit_input(cls, txin):
|
||||
has_nonzero_witness = txin.get('witness', '00') != '00'
|
||||
has_nonzero_witness = txin.get('witness', '00') not in ('00', None)
|
||||
return cls.is_segwit_inputtype(txin['type']) or has_nonzero_witness
|
||||
|
||||
@classmethod
|
||||
|
@ -768,6 +777,11 @@ class Transaction:
|
|||
_type = txin['type']
|
||||
if _type == 'coinbase':
|
||||
return txin['scriptSig']
|
||||
|
||||
script_sig = txin.get('scriptSig', None)
|
||||
if script_sig is not None:
|
||||
return script_sig
|
||||
|
||||
pubkeys, sig_list = self.get_siglist(txin, estimate_size)
|
||||
script = ''.join(push_script(x) for x in sig_list)
|
||||
if _type == 'p2pk':
|
||||
|
@ -1035,7 +1049,8 @@ class Transaction:
|
|||
sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der)
|
||||
if not public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der):
|
||||
raise Exception('Sanity check verifying our own signature failed.')
|
||||
txin['signatures'][j] = bh2u(sig) + '01'
|
||||
sig = bh2u(sig) + '01'
|
||||
self.add_signature_to_txin(txin, j, sig)
|
||||
#txin['x_pubkeys'][j] = pubkey
|
||||
txin['pubkeys'][j] = pubkey # needed for fd keys
|
||||
self._inputs[i] = txin
|
||||
|
|
|
@ -643,7 +643,8 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
|
|||
sig_r = int(signed['sig'][:64], 16)
|
||||
sig_s = int(signed['sig'][64:], 16)
|
||||
sig = sigencode_der(sig_r, sig_s, generator_secp256k1.order())
|
||||
txin['signatures'][ii] = to_hexstr(sig) + '01'
|
||||
sig = to_hexstr(sig) + '01'
|
||||
Transaction.add_signature_to_txin(txin, ii, sig)
|
||||
tx._inputs[i] = txin
|
||||
except UserCancelled:
|
||||
raise
|
||||
|
|
|
@ -498,7 +498,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||
|
||||
for i, txin in enumerate(tx.inputs()):
|
||||
signingPos = inputs[i][4]
|
||||
txin['signatures'][signingPos] = bh2u(signatures[i])
|
||||
Transaction.add_signature_to_txin(txin, signingPos, bh2u(signatures[i]))
|
||||
tx.raw = tx.serialize()
|
||||
|
||||
@test_pin_unlocked
|
||||
|
|
Loading…
Add table
Reference in a new issue