Skip to content

Commit

Permalink
Add support for nested tuples to event filters and logs
Browse files Browse the repository at this point in the history
- Nested tuples seemed to be broken when parsing event filters. This commit piggy backs off previous work and uses the collapse_if_tuple() method in the _build_argument_filters_from_even_abi() method. From testing, this seemes to have been a missing piece to get these issues resolved and the added test passing.
- Remove testing nested tuple method from tests that require the test id enum. These were added in the previous commit. Instead, add a test specific to testing the new method / event for tuples.
- Add testing for the new nested tuple function + event in the emitter contract.
  • Loading branch information
fselmo committed Jan 13, 2022
1 parent b47e2a5 commit bf9f60b
Show file tree
Hide file tree
Showing 11 changed files with 368 additions and 197 deletions.
3 changes: 1 addition & 2 deletions tests/core/contracts/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ def strict_emitter(w3_strict_abi,

wait_for_block(w3)
deploy_txn_hash = StrictEmitter.constructor().transact(
{'from': w3.eth.coinbase, 'gas': 1000000}
{'from': w3.eth.coinbase, 'gas': 10000000}
)
deploy_receipt = wait_for_transaction(w3, deploy_txn_hash)
contract_address = address_conversion_func(deploy_receipt['contractAddress'])
Expand Down Expand Up @@ -943,7 +943,6 @@ class LogFunctions:
LogTripleWithIndex = 10
LogQuadrupleWithIndex = 11
LogBytes = 12
LogStructArgs = 13


@pytest.fixture()
Expand Down
8 changes: 5 additions & 3 deletions tests/core/contracts/contract_sources/Emitter.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.8.7;
pragma solidity ^0.8.11;


contract Emitter {
Expand All @@ -11,7 +11,6 @@ contract Emitter {
event LogString(string v);
event LogBytes(bytes v);

// Indexed
event LogSingleWithIndex(uint indexed arg0);
event LogSingleAnonymous(uint indexed arg0) anonymous;
event LogDoubleWithIndex(uint arg0, uint indexed arg1);
Expand All @@ -23,10 +22,13 @@ contract Emitter {
event LogAddressIndexed(address indexed arg0, address arg1);
event LogAddressNotIndexed(address arg0, address arg1);

// Nested type functionality
struct NestedTestTuple {
uint c;
}
struct TestTuple {
uint a;
uint b;
NestedTestTuple nested;
}
event LogStructArgs(uint arg0, TestTuple arg1);

Expand Down
42 changes: 26 additions & 16 deletions tests/core/contracts/test_extracting_event_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def Emitter(web3, EMITTER):
@pytest.fixture()
def emitter(web3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
wait_for_block(web3)
deploy_txn_hash = Emitter.constructor().transact({'from': web3.eth.coinbase, 'gas': 1000000})
deploy_txn_hash = Emitter.constructor().transact({'from': web3.eth.coinbase, 'gas': 10000000})
deploy_receipt = web3.eth.wait_for_transaction_receipt(deploy_txn_hash)
contract_address = address_conversion_func(deploy_receipt['contractAddress'])

Expand Down Expand Up @@ -148,12 +148,6 @@ def dup_txn_receipt(
[12345, 54321, 98765, 56789],
{'arg0': 12345, 'arg1': 54321, 'arg2': 98765, 'arg3': 56789},
),
(
'logStruct',
'LogStructArgs',
[12345, {'a': 0, 'b': 1}],
{'arg0': 12345, 'arg1': {'a': 0, 'b': 1}},
)
)
)
def test_event_data_extraction(web3,
Expand Down Expand Up @@ -337,7 +331,7 @@ def test_argument_extraction_strict_bytes_types(w3_strict_abi,
emitter_log_topics):
arg_0 = [b'12']
arg_1 = [b'12']
txn_hash = strict_emitter.functions.logListArgs(arg_0, arg_1).transact()
txn_hash = strict_emitter.functions.logListArgs(arg_0, arg_1).transact({'gas': 25000})
txn_receipt = wait_for_transaction(w3_strict_abi, txn_hash)

assert len(txn_receipt['logs']) == 1
Expand Down Expand Up @@ -566,17 +560,17 @@ def test_argument_extraction_strict_bytes_types(w3_strict_abi,
),
(
'logStruct',
'logStructArgs',
[12345, {'a': 0, 'b': 1}],
{'arg0': 12345, 'arg1': {'a': 0, 'b': 1}},
'LogStructArgs',
[1, (2, 3, (4,))],
{'arg0': 1, 'arg1': (2, 3, (4,))},
'The event signature did not match the provided ABI',
True,
),
(
'logStruct',
'logStructArgs',
[12345, {'a': 0, 'b': 1}],
{'arg0': 12345, 'arg1': {'a': 0, 'b': 1}},
'LogStructArgs',
[1, (2, 3, (4,))],
{'arg0': 1, 'arg1': (2, 3, (4,))},
'The event signature did not match the provided ABI',
False,
),
Expand All @@ -595,8 +589,13 @@ def test_event_rich_log(
expected_args):

emitter_fn = emitter.functions[contract_fn]
event_id = getattr(emitter_event_ids, event_name)
txn_hash = emitter_fn(event_id, *call_args).transact()
try:
event_id = getattr(emitter_event_ids, event_name)
txn_hash = emitter_fn(event_id, *call_args).transact()
except AttributeError:
# Some tests do not rely on the event_id. Rather than changing this test too much,
# bypass this here and just call the function with the provided args.
txn_hash = emitter_fn(*call_args).transact()
txn_receipt = wait_for_transaction(web3, txn_hash)

event_instance = emitter.events[event_name]()
Expand Down Expand Up @@ -759,3 +758,14 @@ def test_single_log_processing_with_errors(

with pytest.raises(LogTopicError, match="Expected 1 log topics. Got 0"):
event_instance.processLog(dup_txn_receipt['logs'][0])


def test_event_with_nested_tuple_types(web3, emitter):
struct_args_filter = emitter.events.LogStructArgs.createFilter(fromBlock=0)

tx_hash = emitter.functions.logStruct(1, (2, 3, (4, ))).transact({'gas': 100000})
web3.eth.wait_for_transaction_receipt(tx_hash)

entries = struct_args_filter.get_all_entries()

assert entries != []
2 changes: 1 addition & 1 deletion tests/core/contracts/test_extracting_event_data_old.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def Emitter(web3, EMITTER):
@pytest.fixture()
def emitter(web3, Emitter, wait_for_transaction, wait_for_block, address_conversion_func):
wait_for_block(web3)
deploy_txn_hash = Emitter.constructor().transact({'from': web3.eth.coinbase, 'gas': 1000000})
deploy_txn_hash = Emitter.constructor().transact({'from': web3.eth.coinbase, 'gas': 10000000})
deploy_receipt = web3.eth.wait_for_transaction_receipt(deploy_txn_hash)
contract_address = address_conversion_func(deploy_receipt['contractAddress'])

Expand Down
2 changes: 1 addition & 1 deletion tests/core/filtering/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def emitter(web3, Emitter, wait_for_transaction, wait_for_block, address_convers
wait_for_block(web3)
deploy_txn_hash = Emitter.constructor().transact({
'from': web3.eth.coinbase,
'gas': 1000000,
'gas': 10000000,
'maxFeePerGas': 10 ** 9,
'maxPriorityFeePerGas': 10 ** 9,
})
Expand Down
2 changes: 1 addition & 1 deletion tests/core/filtering/test_contract_data_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def emitter(web3, Emitter, wait_for_transaction, wait_for_block, address_convers
wait_for_block(web3)
deploy_txn_hash = Emitter.constructor().transact({
'from': web3.eth.coinbase,
'gas': 1000000,
'gas': 10000000,
'maxFeePerGas': 10 ** 9,
'maxPriorityFeePerGas': 10 ** 9,
})
Expand Down
2 changes: 1 addition & 1 deletion tests/core/filtering/test_contract_getLogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def test_contract_get_available_events(
"""We can iterate over available contract events"""
contract = emitter
events = list(contract.events)
assert len(events) == 18
assert len(events) == 19


def test_contract_getLogs_all(
Expand Down
2 changes: 1 addition & 1 deletion tests/core/filtering/test_contract_topic_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def emitter(web3, Emitter, wait_for_transaction, wait_for_block, address_convers
wait_for_block(web3)
deploy_txn_hash = Emitter.constructor().transact({
'from': web3.eth.coinbase,
'gas': 1000000,
'gas': 10000000,
'maxFeePerGas': 10 ** 9,
'maxPriorityFeePerGas': 10 ** 9,
})
Expand Down
12 changes: 7 additions & 5 deletions web3/_utils/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
to_hex,
to_tuple,
)
from eth_utils.abi import collapse_if_tuple
from eth_utils.abi import (
collapse_if_tuple,
)
from eth_utils.curried import (
apply_formatter_if,
)
Expand Down Expand Up @@ -194,7 +196,7 @@ def get_event_abi_types_for_decoding(event_inputs: Sequence[ABIEventParams]) ->
if input_abi['indexed'] and is_dynamic_sized_type(input_abi['type']):
yield 'bytes32'
else:
yield collapse_if_tuple(input_abi)
yield collapse_if_tuple(dict(input_abi))


@curry
Expand Down Expand Up @@ -431,9 +433,9 @@ def _build_argument_filters_from_event_abi(
key = item['name']
value: 'BaseArgumentFilter'
if item['indexed'] is True:
value = TopicArgumentFilter(abi_codec=abi_codec, arg_type=item['type'])
value = TopicArgumentFilter(abi_codec=abi_codec, arg_type=collapse_if_tuple(dict(item)))
else:
value = DataArgumentFilter(arg_type=item['type'])
value = DataArgumentFilter(arg_type=collapse_if_tuple(dict(item)))
yield key, value


Expand Down Expand Up @@ -479,7 +481,7 @@ class DataArgumentFilter(BaseArgumentFilter):
# type ignore b/c conflict with BaseArgumentFilter.match_values type
@property
def match_values(self) -> Tuple[TypeStr, Tuple[Any, ...]]: # type: ignore
return (self.arg_type, self._match_values)
return self.arg_type, self._match_values


class TopicArgumentFilter(BaseArgumentFilter):
Expand Down
1 change: 1 addition & 0 deletions web3/_utils/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class TransactionFilter(Filter):
class LogFilter(Filter):
data_filter_set = None
data_filter_set_regex = None
data_filter_set_function = None
log_entry_formatter = None
filter_params: FilterParams = None
builder: EventFilterBuilder = None
Expand Down
Loading

0 comments on commit bf9f60b

Please sign in to comment.