fix #3899; and more aggressively catch exceptions in tx.deserialize()
This commit is contained in:
@@ -32,6 +32,8 @@ from .util import print_error, profiler
|
||||
from . import bitcoin
|
||||
from .bitcoin import *
|
||||
import struct
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
#
|
||||
# Workalike python implementation of Bitcoin's CDataStream class.
|
||||
@@ -303,7 +305,8 @@ def parse_scriptSig(d, _bytes):
|
||||
decoded = [ x for x in script_GetOp(_bytes) ]
|
||||
except Exception as e:
|
||||
# coinbase transactions raise an exception
|
||||
print_error("cannot find address in input script", bh2u(_bytes))
|
||||
print_error("parse_scriptSig: cannot find address in input script (coinbase?)",
|
||||
bh2u(_bytes))
|
||||
return
|
||||
|
||||
match = [ opcodes.OP_PUSHDATA4 ]
|
||||
@@ -334,9 +337,9 @@ def parse_scriptSig(d, _bytes):
|
||||
d['pubkeys'] = ["(pubkey)"]
|
||||
return
|
||||
|
||||
# non-generated TxIn transactions push a signature
|
||||
# (seventy-something bytes) and then their public key
|
||||
# (65 bytes) onto the stack:
|
||||
# p2pkh TxIn transactions push a signature
|
||||
# (71-73 bytes) and then their public key
|
||||
# (33 or 65 bytes) onto the stack:
|
||||
match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ]
|
||||
if match_decoded(decoded, match):
|
||||
sig = bh2u(decoded[0][1])
|
||||
@@ -345,7 +348,8 @@ def parse_scriptSig(d, _bytes):
|
||||
signatures = parse_sig([sig])
|
||||
pubkey, address = xpubkey_to_address(x_pubkey)
|
||||
except:
|
||||
print_error("cannot find address in input script", bh2u(_bytes))
|
||||
print_error("parse_scriptSig: cannot find address in input script (p2pkh?)",
|
||||
bh2u(_bytes))
|
||||
return
|
||||
d['type'] = 'p2pkh'
|
||||
d['signatures'] = signatures
|
||||
@@ -357,19 +361,26 @@ def parse_scriptSig(d, _bytes):
|
||||
|
||||
# p2sh transaction, m of n
|
||||
match = [ opcodes.OP_0 ] + [ opcodes.OP_PUSHDATA4 ] * (len(decoded) - 1)
|
||||
if not match_decoded(decoded, match):
|
||||
print_error("cannot find address in input script", bh2u(_bytes))
|
||||
if match_decoded(decoded, match):
|
||||
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
||||
try:
|
||||
m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1])
|
||||
except NotRecognizedRedeemScript:
|
||||
# we could still guess:
|
||||
# d['address'] = hash160_to_p2sh(hash_160(decoded[-1][1]))
|
||||
return
|
||||
# write result in d
|
||||
d['type'] = 'p2sh'
|
||||
d['num_sig'] = m
|
||||
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)))
|
||||
return
|
||||
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
||||
m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1])
|
||||
# write result in d
|
||||
d['type'] = 'p2sh'
|
||||
d['num_sig'] = m
|
||||
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)))
|
||||
|
||||
print_error("parse_scriptSig: cannot find address in input script (unknown)",
|
||||
bh2u(_bytes))
|
||||
|
||||
|
||||
def parse_redeemScript(s):
|
||||
@@ -380,7 +391,7 @@ def parse_redeemScript(s):
|
||||
op_n = opcodes.OP_1 + n - 1
|
||||
match_multisig = [ op_m ] + [opcodes.OP_PUSHDATA4]*n + [ op_n, opcodes.OP_CHECKMULTISIG ]
|
||||
if not match_decoded(dec2, match_multisig):
|
||||
print_error("cannot find address in input script", bh2u(s))
|
||||
print_error("parse_redeemScript: not multisig", bh2u(s))
|
||||
raise NotRecognizedRedeemScript()
|
||||
x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
|
||||
pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
|
||||
@@ -436,7 +447,11 @@ def parse_input(vds):
|
||||
d['num_sig'] = 0
|
||||
if scriptSig:
|
||||
d['scriptSig'] = bh2u(scriptSig)
|
||||
parse_scriptSig(d, scriptSig)
|
||||
try:
|
||||
parse_scriptSig(d, scriptSig)
|
||||
except BaseException:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print_error('failed to parse scriptSig', bh2u(scriptSig))
|
||||
else:
|
||||
d['scriptSig'] = ''
|
||||
|
||||
@@ -465,25 +480,40 @@ def parse_witness(vds, txin):
|
||||
# between p2wpkh and p2wsh; we do this based on number of witness items,
|
||||
# hence (FIXME) p2wsh with n==2 (maybe n==1 ?) will probably fail.
|
||||
# If v==0 and n==2, we need parent scriptPubKey to distinguish between p2wpkh and p2wsh.
|
||||
if txin['type'] == 'coinbase':
|
||||
pass
|
||||
elif txin['type'] == 'p2wsh-p2sh' or n > 2:
|
||||
try:
|
||||
m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1]))
|
||||
except NotRecognizedRedeemScript:
|
||||
try:
|
||||
if txin['type'] == 'coinbase':
|
||||
pass
|
||||
elif txin['type'] == 'p2wsh-p2sh' or n > 2:
|
||||
try:
|
||||
m, n, x_pubkeys, pubkeys, witnessScript = parse_redeemScript(bfh(w[-1]))
|
||||
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
|
||||
if not txin.get('scriptSig'): # native segwit script
|
||||
txin['type'] = 'p2wsh'
|
||||
txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript'])
|
||||
elif txin['type'] == 'p2wpkh-p2sh' or n == 2:
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [w[1]]
|
||||
txin['pubkeys'] = [safe_parse_pubkey(w[1])]
|
||||
txin['signatures'] = parse_sig([w[0]])
|
||||
if not txin.get('scriptSig'): # native segwit script
|
||||
txin['type'] = 'p2wpkh'
|
||||
txin['address'] = bitcoin.public_key_to_p2wpkh(bfh(txin['pubkeys'][0]))
|
||||
else:
|
||||
raise UnknownTxinType()
|
||||
txin['signatures'] = parse_sig(w[1:-1])
|
||||
txin['num_sig'] = m
|
||||
txin['x_pubkeys'] = x_pubkeys
|
||||
txin['pubkeys'] = pubkeys
|
||||
txin['witnessScript'] = witnessScript
|
||||
elif txin['type'] == 'p2wpkh-p2sh' or n == 2:
|
||||
txin['num_sig'] = 1
|
||||
txin['x_pubkeys'] = [w[1]]
|
||||
txin['pubkeys'] = [safe_parse_pubkey(w[1])]
|
||||
txin['signatures'] = parse_sig([w[0]])
|
||||
else:
|
||||
raise UnknownTxinType()
|
||||
except UnknownTxinType:
|
||||
txin['type'] = 'unknown'
|
||||
# FIXME: GUI might show 'unknown' address (e.g. for a non-multisig p2wsh)
|
||||
except BaseException:
|
||||
txin['type'] = 'unknown'
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print_error('failed to parse witness', txin.get('witness'))
|
||||
|
||||
|
||||
def parse_output(vds, i):
|
||||
d = {}
|
||||
@@ -513,20 +543,7 @@ def deserialize(raw):
|
||||
if is_segwit:
|
||||
for i in range(n_vin):
|
||||
txin = d['inputs'][i]
|
||||
try:
|
||||
parse_witness(vds, txin)
|
||||
except UnknownTxinType:
|
||||
txin['type'] = 'unknown'
|
||||
# FIXME: GUI might show 'unknown' address (e.g. for a non-multisig p2wsh)
|
||||
continue
|
||||
# segwit-native script
|
||||
if not txin.get('scriptSig'):
|
||||
if txin['num_sig'] == 1:
|
||||
txin['type'] = 'p2wpkh'
|
||||
txin['address'] = bitcoin.public_key_to_p2wpkh(bfh(txin['pubkeys'][0]))
|
||||
else:
|
||||
txin['type'] = 'p2wsh'
|
||||
txin['address'] = bitcoin.script_to_p2wsh(txin['witnessScript'])
|
||||
parse_witness(vds, txin)
|
||||
d['lockTime'] = vds.read_uint32()
|
||||
return d
|
||||
|
||||
|
||||
Reference in New Issue
Block a user