mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-02 18:25:21 +00:00
fix #3899; and more aggressively catch exceptions in tx.deserialize()
This commit is contained in:
parent
cc19de9db3
commit
4b6a3e2e5d
2 changed files with 73 additions and 51 deletions
|
@ -235,6 +235,11 @@ class TestTransaction(unittest.TestCase):
|
||||||
tx = transaction.Transaction('0100000000010160f84fdcda039c3ca1b20038adea2d49a53db92f7c467e8def13734232bb610804000000232200202814720f16329ab81cb8867c4d447bd13255931f23e6655944c9ada1797fcf88ffffffff0ba3dcfc04000000001976a91488124a57c548c9e7b1dd687455af803bd5765dea88acc9f44900000000001976a914da55045a0ccd40a56ce861946d13eb861eb5f2d788ac49825e000000000017a914ca34d4b190e36479aa6e0023cfe0a8537c6aa8dd87680c0d00000000001976a914651102524c424b2e7c44787c4f21e4c54dffafc088acf02fa9000000000017a914ee6c596e6f7066466d778d4f9ba633a564a6e95d874d250900000000001976a9146ca7976b48c04fd23867748382ee8401b1d27c2988acf5119600000000001976a914cf47d5dcdba02fd547c600697097252d38c3214a88ace08a12000000000017a914017bef79d92d5ec08c051786bad317e5dd3befcf87e3d76201000000001976a9148ec1b88b66d142bcbdb42797a0fd402c23e0eec288ac718f6900000000001976a914e66344472a224ce6f843f2989accf435ae6a808988ac65e51300000000001976a914cad6717c13a2079066f876933834210ebbe68c3f88ac0347304402201a4907c4706104320313e182ecbb1b265b2d023a79586671386de86bb47461590220472c3db9fc99a728ebb9b555a72e3481d20b181bd059a9c1acadfb853d90c96c01210338a46f2a54112fef8803c8478bc17e5f8fc6a5ec276903a946c1fafb2e3a8b181976a914eda8660085bf607b82bd18560ca8f3a9ec49178588ac00000000')
|
tx = transaction.Transaction('0100000000010160f84fdcda039c3ca1b20038adea2d49a53db92f7c467e8def13734232bb610804000000232200202814720f16329ab81cb8867c4d447bd13255931f23e6655944c9ada1797fcf88ffffffff0ba3dcfc04000000001976a91488124a57c548c9e7b1dd687455af803bd5765dea88acc9f44900000000001976a914da55045a0ccd40a56ce861946d13eb861eb5f2d788ac49825e000000000017a914ca34d4b190e36479aa6e0023cfe0a8537c6aa8dd87680c0d00000000001976a914651102524c424b2e7c44787c4f21e4c54dffafc088acf02fa9000000000017a914ee6c596e6f7066466d778d4f9ba633a564a6e95d874d250900000000001976a9146ca7976b48c04fd23867748382ee8401b1d27c2988acf5119600000000001976a914cf47d5dcdba02fd547c600697097252d38c3214a88ace08a12000000000017a914017bef79d92d5ec08c051786bad317e5dd3befcf87e3d76201000000001976a9148ec1b88b66d142bcbdb42797a0fd402c23e0eec288ac718f6900000000001976a914e66344472a224ce6f843f2989accf435ae6a808988ac65e51300000000001976a914cad6717c13a2079066f876933834210ebbe68c3f88ac0347304402201a4907c4706104320313e182ecbb1b265b2d023a79586671386de86bb47461590220472c3db9fc99a728ebb9b555a72e3481d20b181bd059a9c1acadfb853d90c96c01210338a46f2a54112fef8803c8478bc17e5f8fc6a5ec276903a946c1fafb2e3a8b181976a914eda8660085bf607b82bd18560ca8f3a9ec49178588ac00000000')
|
||||||
self.assertEqual('e9933221a150f78f9f224899f8568ff6422ffcc28ca3d53d87936368ff7c4b1d', tx.txid())
|
self.assertEqual('e9933221a150f78f9f224899f8568ff6422ffcc28ca3d53d87936368ff7c4b1d', tx.txid())
|
||||||
|
|
||||||
|
# input: p2sh, not multisig
|
||||||
|
def test_txid_regression_issue_3899(self):
|
||||||
|
tx = transaction.Transaction('0100000004328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c010000000b0009630330472d5fae685bffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c020000000b0009630359646d5fae6858ffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c030000000b000963034bd4715fae6854ffffffff328685b0352c981d3d451b471ae3bfc78b82565dc2a54049a81af273f0a9fd9c040000000b000963036de8705fae6860ffffffff0130750000000000001976a914b5abca61d20f9062fb1fdbb880d9d93bac36675188ac00000000')
|
||||||
|
self.assertEqual('f570d5d1e965ee61bcc7005f8fefb1d3abbed9d7ddbe035e2a68fa07e5fc4a0d', tx.txid())
|
||||||
|
|
||||||
|
|
||||||
class NetworkMock(object):
|
class NetworkMock(object):
|
||||||
|
|
||||||
|
|
|
@ -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,11 +361,14 @@ 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))
|
|
||||||
return
|
|
||||||
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
|
||||||
|
try:
|
||||||
m, n, x_pubkeys, pubkeys, redeemScript = parse_redeemScript(decoded[-1][1])
|
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
|
# write result in d
|
||||||
d['type'] = 'p2sh'
|
d['type'] = 'p2sh'
|
||||||
d['num_sig'] = m
|
d['num_sig'] = m
|
||||||
|
@ -370,6 +377,10 @@ def parse_scriptSig(d, _bytes):
|
||||||
d['pubkeys'] = pubkeys
|
d['pubkeys'] = pubkeys
|
||||||
d['redeemScript'] = redeemScript
|
d['redeemScript'] = redeemScript
|
||||||
d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
|
d['address'] = hash160_to_p2sh(hash_160(bfh(redeemScript)))
|
||||||
|
return
|
||||||
|
|
||||||
|
print_error("parse_scriptSig: cannot find address in input script (unknown)",
|
||||||
|
bh2u(_bytes))
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
try:
|
||||||
parse_scriptSig(d, scriptSig)
|
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,6 +480,7 @@ 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.
|
||||||
|
try:
|
||||||
if txin['type'] == 'coinbase':
|
if txin['type'] == 'coinbase':
|
||||||
pass
|
pass
|
||||||
elif txin['type'] == 'p2wsh-p2sh' or n > 2:
|
elif txin['type'] == 'p2wsh-p2sh' or n > 2:
|
||||||
|
@ -477,13 +493,27 @@ def parse_witness(vds, txin):
|
||||||
txin['x_pubkeys'] = x_pubkeys
|
txin['x_pubkeys'] = x_pubkeys
|
||||||
txin['pubkeys'] = pubkeys
|
txin['pubkeys'] = pubkeys
|
||||||
txin['witnessScript'] = witnessScript
|
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:
|
elif txin['type'] == 'p2wpkh-p2sh' or n == 2:
|
||||||
txin['num_sig'] = 1
|
txin['num_sig'] = 1
|
||||||
txin['x_pubkeys'] = [w[1]]
|
txin['x_pubkeys'] = [w[1]]
|
||||||
txin['pubkeys'] = [safe_parse_pubkey(w[1])]
|
txin['pubkeys'] = [safe_parse_pubkey(w[1])]
|
||||||
txin['signatures'] = parse_sig([w[0]])
|
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:
|
else:
|
||||||
raise UnknownTxinType()
|
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):
|
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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue