Fix address[] return types

This commit is contained in:
Piper Merriam 2016-09-06 15:05:33 -06:00
parent 8d8b9dcd4a
commit e11c87cd13
7 changed files with 146 additions and 89 deletions

View File

@ -0,0 +1,35 @@
import pytest
from eth_abi import encode_single
from web3.utils.abi import normalize_return_type
@pytest.mark.parametrize(
'data_type,data_value,expected_value',
(
(
'bytes32',
'arst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
'arst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
),
(
'address',
'd3cda913deb6f67967b99d67acdfa1712c293601',
'0xd3cda913deb6f67967b99d67acdfa1712c293601',
),
(
'address[]',
[
'd3cda913deb6f67967b99d67acdfa1712c293601',
'bb9bc244d798123fde783fcc1c72d3bb8c189413',
],
[
'0xd3cda913deb6f67967b99d67acdfa1712c293601',
'0xbb9bc244d798123fde783fcc1c72d3bb8c189413',
],
),
)
)
def test_normalizing_return_values(data_type, data_value, expected_value):
actual_value = normalize_return_type(data_type, data_value)
assert actual_value == expected_value

View File

@ -1,7 +1,7 @@
import pytest
from web3.utils.abi import (
from web3.utils.events import (
construct_event_data_set,
)

View File

@ -1,7 +1,7 @@
import pytest
from web3.utils.abi import (
from web3.utils.events import (
construct_event_topic_set,
)

View File

@ -35,6 +35,7 @@ from web3.utils.abi import (
check_if_arguments_can_be_encoded,
function_abi_to_4byte_selector,
merge_args_and_kwargs,
normalize_return_type,
)
from web3.utils.decorators import (
combomethod,
@ -642,10 +643,11 @@ def call_contract_function(contract,
output_data = decode_abi(output_types, return_data)
normalized_data = [
add_0x_prefix(data_value) if data_type == 'address' else data_value
normalize_return_type(data_type, data_value)
for data_type, data_value
in zip(output_types, output_data)
]
if len(normalized_data) == 1:
return normalized_data[0]
else:

View File

@ -2,10 +2,8 @@ import itertools
from eth_abi.abi import (
process_type,
encode_single,
)
from .encoding import encode_hex
from .crypto import sha3
from .string import (
coerce_args_to_bytes,
@ -226,85 +224,16 @@ def event_abi_to_log_topic(event_abi):
@coerce_return_to_text
def construct_event_topic_set(event_abi, arguments=None):
if arguments is None:
arguments = {}
if isinstance(arguments, (list, tuple)):
if len(arguments) != len(event_abi['inputs']):
raise ValueError(
"When passing an argument list, the number of arguments must "
"match the event constructor."
)
arguments = {
arg['name']: [arg_value]
for arg, arg_value
in zip(event_abi['inputs'], arguments)
}
def normalize_return_type(data_type, data_value):
try:
base, sub, arrlist = data_type
except ValueError:
base, sub, arrlist = process_type(data_type)
normalized_args = {
key: value if is_array(value) else [value]
for key, value in arguments.items()
}
event_topic = event_abi_to_log_topic(event_abi)
indexed_args = get_indexed_event_inputs(event_abi)
zipped_abi_and_args = [
(arg, normalized_args.get(arg['name'], [None]))
for arg in indexed_args
]
encoded_args = [
[
None if option is None else encode_hex(encode_single(arg['type'], option))
for option in arg_options]
for arg, arg_options in zipped_abi_and_args
]
topics = [
[event_topic] + list(permutation)
if any(value is not None for value in permutation)
else [event_topic]
for permutation in itertools.product(*encoded_args)
]
return topics
@coerce_return_to_text
def construct_event_data_set(event_abi, arguments=None):
if arguments is None:
arguments = {}
if isinstance(arguments, (list, tuple)):
if len(arguments) != len(event_abi['inputs']):
raise ValueError(
"When passing an argument list, the number of arguments must "
"match the event constructor."
)
arguments = {
arg['name']: [arg_value]
for arg, arg_value
in zip(event_abi['inputs'], arguments)
}
normalized_args = {
key: value if is_array(value) else [value]
for key, value in arguments.items()
}
indexed_args = exclude_indexed_event_inputs(event_abi)
zipped_abi_and_args = [
(arg, normalized_args.get(arg['name'], [None]))
for arg in indexed_args
]
encoded_args = [
[
None if option is None else encode_hex(encode_single(arg['type'], option))
for option in arg_options]
for arg, arg_options in zipped_abi_and_args
]
topics = [
list(permutation)
if any(value is not None for value in permutation)
else []
for permutation in itertools.product(*encoded_args)
]
return topics
if arrlist:
sub_type = (base, sub, arrlist[:-1])
return [normalize_return_type(sub_type, sub_value) for sub_value in data_value]
elif base == 'address':
return add_0x_prefix(data_value)
else:
return data_value

View File

@ -3,17 +3,108 @@ import itertools
from eth_abi import (
decode_abi,
decode_single,
encode_single,
)
from .encoding import encode_hex
from .types import (
is_array,
)
from .string import (
coerce_return_to_text,
)
from .abi import (
get_abi_input_types,
get_abi_input_names,
get_indexed_event_inputs,
exclude_indexed_event_inputs,
event_abi_to_log_topic,
)
ABI_EVENT_TYPE_MAP = {
}
@coerce_return_to_text
def construct_event_topic_set(event_abi, arguments=None):
if arguments is None:
arguments = {}
if isinstance(arguments, (list, tuple)):
if len(arguments) != len(event_abi['inputs']):
raise ValueError(
"When passing an argument list, the number of arguments must "
"match the event constructor."
)
arguments = {
arg['name']: [arg_value]
for arg, arg_value
in zip(event_abi['inputs'], arguments)
}
normalized_args = {
key: value if is_array(value) else [value]
for key, value in arguments.items()
}
event_topic = event_abi_to_log_topic(event_abi)
indexed_args = get_indexed_event_inputs(event_abi)
zipped_abi_and_args = [
(arg, normalized_args.get(arg['name'], [None]))
for arg in indexed_args
]
encoded_args = [
[
None if option is None else encode_hex(encode_single(arg['type'], option))
for option in arg_options]
for arg, arg_options in zipped_abi_and_args
]
topics = [
[event_topic] + list(permutation)
if any(value is not None for value in permutation)
else [event_topic]
for permutation in itertools.product(*encoded_args)
]
return topics
@coerce_return_to_text
def construct_event_data_set(event_abi, arguments=None):
if arguments is None:
arguments = {}
if isinstance(arguments, (list, tuple)):
if len(arguments) != len(event_abi['inputs']):
raise ValueError(
"When passing an argument list, the number of arguments must "
"match the event constructor."
)
arguments = {
arg['name']: [arg_value]
for arg, arg_value
in zip(event_abi['inputs'], arguments)
}
normalized_args = {
key: value if is_array(value) else [value]
for key, value in arguments.items()
}
indexed_args = exclude_indexed_event_inputs(event_abi)
zipped_abi_and_args = [
(arg, normalized_args.get(arg['name'], [None]))
for arg in indexed_args
]
encoded_args = [
[
None if option is None else encode_hex(encode_single(arg['type'], option))
for option in arg_options]
for arg, arg_options in zipped_abi_and_args
]
topics = [
list(permutation)
if any(value is not None for value in permutation)
else []
for permutation in itertools.product(*encoded_args)
]
return topics
def coerce_event_abi_types_for_decoding(input_types):

View File

@ -6,7 +6,7 @@ from .types import (
is_string,
is_array,
)
from .abi import (
from .events import (
construct_event_topic_set,
construct_event_data_set,
)