Skip to content

Commit

Permalink
Merge pull request #52 from blockcypher/nulldata-fix
Browse files Browse the repository at this point in the history
fix for null-data not needing an address assertion
  • Loading branch information
Michael Flaxman committed Sep 2, 2016
2 parents adc797c + f787d7c commit 79e05b0
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 19 deletions.
31 changes: 19 additions & 12 deletions blockcypher/api.py
Expand Up @@ -1644,23 +1644,30 @@ def create_unsigned_tx(inputs, outputs, change_address=None,
outputs_cleaned = []
sweep_funds = False
for output in outputs:
clean_output = {}
assert 'value' in output, output
assert type(output['value']) is int, output['value']
if output['value'] == -1:
sweep_funds = True
assert not change_address, 'Change Address Supplied for Sweep TX'

# note that API requires the singleton list 'addresses' which is
clean_output['value'] = output['value']

# no address required for null-data outputs
if output.get('script_type') == 'null-data':
assert output['value'] == 0
assert 'script' in output, output
clean_output['script_type'] = 'null-data'
clean_output['script'] = output['script']
# but note that API requires the singleton list 'addresses' which is
# intentionally hidden away from the user here
assert 'address' in output, output
assert is_valid_address_for_coinsymbol(
b58_address=output['address'],
coin_symbol=coin_symbol,
)
outputs_cleaned.append({
'value': output['value'],
'addresses': [output['address'], ],
})
else:
assert 'address' in output, output
assert is_valid_address_for_coinsymbol(
b58_address=output['address'],
coin_symbol=coin_symbol,
)
clean_output['addresses'] = [output['address']]
outputs_cleaned.append(clean_output)

if change_address:
assert is_valid_address_for_coinsymbol(b58_address=change_address,
Expand Down Expand Up @@ -1748,7 +1755,7 @@ def verify_unsigned_tx(unsigned_tx, outputs, inputs=None, sweep_funds=False,
err_msg = 'tosign_tx not in API response:\n%s' % unsigned_tx
return False, err_msg

output_addr_list = [x['address'] for x in outputs]
output_addr_list = [x['address'] for x in outputs if x.get('address') != None]
if change_address:
output_addr_list.append(change_address)

Expand Down
16 changes: 10 additions & 6 deletions blockcypher/utils.py
Expand Up @@ -174,26 +174,29 @@ def get_txn_outputs(raw_tx_hex, output_addr_list, coin_symbol):
outputs = []
deserialized_tx = deserialize(str(raw_tx_hex))
for out in deserialized_tx.get('outs', []):
output = {'value': out['value']}

# determine if the address is a pubkey address or a script address
# determine if the address is a pubkey address, script address, or op_return
pubkey_addr = script_to_address(out['script'],
vbyte=COIN_SYMBOL_MAPPINGS[coin_symbol]['vbyte_pubkey'])
script_addr = script_to_address(out['script'],
vbyte=COIN_SYMBOL_MAPPINGS[coin_symbol]['vbyte_script'])
nulldata = out['script'] if out['script'][0:2] == '6a' else None
if pubkey_addr in output_addr_set:
address = pubkey_addr
output['address'] = address
elif script_addr in output_addr_set:
address = script_addr
output['address'] = address
elif nulldata:
output['script'] = nulldata
output['script_type'] = 'null-data'
else:
raise Exception('Script %s Does Not Contain a Valid Output Address: %s' % (
out['script'],
output_addr_set,
))

output = {
'value': out['value'],
'address': address,
}
outputs.append(output)
return outputs

Expand All @@ -207,7 +210,8 @@ def compress_txn_outputs(txn_outputs):
{'1abc...': 12345, '1def': 54321, ...}
'''
result_dict = {}
for txn_output in txn_outputs:
outputs = (output for output in txn_outputs if output.get('address'))
for txn_output in outputs:
if txn_output['address'] in result_dict:
result_dict[txn_output['address']] += txn_output['value']
else:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -5,7 +5,7 @@
from distutils.core import setup

setup(name='blockcypher',
version='1.0.71',
version='1.0.72',
description='BlockCypher Python Library',
author='Michael Flaxman',
author_email='mflaxman+blockcypher@gmail.com',
Expand Down
22 changes: 22 additions & 0 deletions test_blockcypher.py
Expand Up @@ -128,6 +128,28 @@ def test_create_ps2h_unsigned(self):
api_key=BC_API_KEY,
)

def test_create_nulldata_unsigned(self):
# This address I previously sent funds to but threw out the private key
create_unsigned_tx(
inputs=[
{'address': 'BwvSPyMWVL1gkp5FZdrGXLpHj2ZJyJYLVB'},
],
outputs=[
# embed some null-data
{
'value': 0,
'script_type': 'null-data',
'script': '6a06010203040506',
},
],
change_address='CFr99841LyMkyX5ZTGepY58rjXJhyNGXHf',
include_tosigntx=True,
# will test signature returned locally:
verify_tosigntx=True,
coin_symbol='bcy',
api_key=BC_API_KEY,
)


class GetAddressDetails(unittest.TestCase):

Expand Down

0 comments on commit 79e05b0

Please sign in to comment.