Skip to content

Commit

Permalink
refactor to final state; rebasing is proving a bit difficult
Browse files Browse the repository at this point in the history
  • Loading branch information
fselmo committed Aug 24, 2023
1 parent 0131e86 commit 02d23e0
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 26 deletions.
28 changes: 28 additions & 0 deletions tests/core/filtering/test_contract_get_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from web3._utils.contract_sources.contract_data._custom_contract_data import (
EMITTER_ENUM,
)
from web3.exceptions import (
Web3ValidationError,
)


def test_contract_get_available_events(
Expand Down Expand Up @@ -166,6 +169,18 @@ def test_get_logs_argument_filters_indexed_and_non_indexed_args(emitter):
assert logs_filter_non_indexed_uint256_and_string[0] == logs_no_filter[0]


def test_get_logs_argument_filters_key_validation(
emitter,
):
with pytest.raises(
Web3ValidationError,
match="all argument names must be present in the contract's event ABI",
):
emitter.events.LogIndexedAndNotIndexed.get_logs(
argument_filters={"nonExistentKey": "Value shouldn't matter"},
)


# --- async --- #


Expand Down Expand Up @@ -364,3 +379,16 @@ async def test_async_get_logs_argument_filters_indexed_and_non_indexed_args(
)
assert len(logs_filter_non_indexed_uint256_and_string) == 1
assert logs_filter_non_indexed_uint256_and_string[0] == logs_no_filter[0]


@pytest.mark.asyncio
async def test_async_get_logs_argument_filters_key_validation(
async_emitter,
):
with pytest.raises(
Web3ValidationError,
match="all argument names must be present in the contract's event ABI",
):
await async_emitter.events.LogIndexedAndNotIndexed.get_logs(
argument_filters={"nonExistentKey": "Value shouldn't matter"},
)
20 changes: 17 additions & 3 deletions web3/contract/async_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
ABIFunctionNotFound,
NoABIFound,
NoABIFunctionsFound,
Web3ValidationError,
)
from web3.types import (
ABI,
Expand All @@ -91,6 +92,9 @@
EventData,
TxParams,
)
from web3.utils import (
get_abi_input_names,
)

if TYPE_CHECKING:
from ens import AsyncENS # noqa: F401
Expand Down Expand Up @@ -156,7 +160,8 @@ async def get_logs(
See also: :func:`web3.middleware.filter.local_filter_middleware`.
:param argument_filters:
:param argument_filters: Filter by argument values. Indexed arguments are
filtered by the node while non-indexed arguments are filtered by the library.
:param fromBlock: block number or "latest", defaults to "latest"
:param toBlock: block number or "latest". Defaults to "latest"
:param block_hash: block hash. blockHash cannot be set at the
Expand All @@ -165,12 +170,21 @@ async def get_logs(
"""
event_abi = self._get_event_abi()

# Call JSON-RPC API
# validate ``argument_filters`` if present
if argument_filters is not None:
event_arg_names = get_abi_input_names(event_abi)
if not all(arg in event_arg_names for arg in argument_filters.keys()):
raise Web3ValidationError(
"When filtering by argument names, all argument names must be "
"present in the contract's event ABI."
)

_filter_params = self._get_event_filter_params(
event_abi, argument_filters, fromBlock, toBlock, block_hash
)

# call JSON-RPC API
logs = await self.w3.eth.get_logs(_filter_params)

# convert raw binary data to Python proxy objects as described by ABI:
all_event_logs = tuple(
get_event_data(self.w3.codec, event_abi, entry) for entry in logs
Expand Down
32 changes: 11 additions & 21 deletions web3/contract/base_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@
TxReceipt,
)

from ..utils import (
get_abi_input_names,
)

if TYPE_CHECKING:
from web3 import ( # noqa: F401
AsyncWeb3,
Expand Down Expand Up @@ -273,25 +269,18 @@ def _process_get_logs_argument_filters(
event_logs: Sequence[EventData],
argument_filters: Optional[Dict[str, Any]],
) -> Iterable[EventData]:
if argument_filters is None or len(event_logs) == 0:
return event_logs

# handle argument filtering for un-indexed args
event_arg_names = get_abi_input_names(event_abi)
if not all(arg in event_arg_names for arg in argument_filters.keys()):
raise TypeError(
"When filtering by argument names, all argument names must be "
"present in the contract's event ABI."
if (
argument_filters is None
or len(event_logs) == 0
or
# if no non-indexed args in argument filters, since indexed args are
# filtered pre-call to ``eth_getLogs`` by building specific ``topics``.
not any(
not arg["indexed"]
for arg in event_abi["inputs"]
if arg["name"] in argument_filters
)

if all(
input_arg["indexed"]
for input_arg in event_abi["inputs"]
if input_arg["name"] in argument_filters.keys()
):
# After validating args, if all args in ``argument_filters`` are indexed,
# then the logs are already filtered by the node in the ``eth_getLogs``
# call.
return event_logs

filtered_logs_by_non_indexed_args = []
Expand Down Expand Up @@ -319,6 +308,7 @@ def _process_get_logs_argument_filters(
break
if match:
break

return filtered_logs_by_non_indexed_args

@combomethod
Expand Down
4 changes: 2 additions & 2 deletions web3/contract/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,12 +177,12 @@ def get_logs(
"present in the contract's event ABI."
)

# Call JSON-RPC API
_filter_params = self._get_event_filter_params(
event_abi, argument_filters, fromBlock, toBlock, block_hash
)

# call JSON-RPC API
logs = self.w3.eth.get_logs(_filter_params)

# convert raw binary data to Python proxy objects as described by ABI:
all_event_logs = tuple(
get_event_data(self.w3.codec, event_abi, entry) for entry in logs
Expand Down

0 comments on commit 02d23e0

Please sign in to comment.