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