diff --git a/newsfragments/3388.feature.rst b/newsfragments/3388.feature.rst new file mode 100644 index 0000000000..5bd70bfe1e --- /dev/null +++ b/newsfragments/3388.feature.rst @@ -0,0 +1 @@ +Properly handle ``InsufficientDataBytes`` errors when processing receipts diff --git a/tests/core/contracts/test_extracting_event_data.py b/tests/core/contracts/test_extracting_event_data.py index 09155a6b5f..29dfe39ce4 100644 --- a/tests/core/contracts/test_extracting_event_data.py +++ b/tests/core/contracts/test_extracting_event_data.py @@ -1,6 +1,10 @@ +import copy import pytest import re +from eth_abi.exceptions import ( + InsufficientDataBytes, +) from eth_utils import ( is_same_address, ) @@ -1233,3 +1237,29 @@ def test_get_all_entries_with_nested_tuple_event_non_strict( assert log_entry.blockNumber == txn_receipt["blockNumber"] assert log_entry.transactionIndex == txn_receipt["transactionIndex"] assert is_same_address(log_entry.address, non_strict_emitter.address) + + +def test_receipt_processing_catches_insufficientdatabytes_error_by_default( + w3, emitter, wait_for_transaction +): + txn_hash = emitter.functions.logListArgs([b"13"], [b"54"]).transact() + txn_receipt = wait_for_transaction(w3, txn_hash) + event_instance = emitter.events.LogListArgs() + + # web3 doesn't generate logs with non-standard lengths, so we have to do it manually + txn_receipt_dict = copy.deepcopy(txn_receipt) + txn_receipt_dict["logs"][0] = dict(txn_receipt_dict["logs"][0]) + txn_receipt_dict["logs"][0]["data"] = txn_receipt_dict["logs"][0]["data"][:-8] + + # WARN is default + assert len(event_instance.process_receipt(txn_receipt_dict)) == 0 + assert len(event_instance.process_receipt(txn_receipt_dict, errors=WARN)) == 0 + assert len(event_instance.process_receipt(txn_receipt_dict, errors=DISCARD)) == 0 + + # IGNORE includes the InsufficientDataBytes error in the log + assert len(event_instance.process_receipt(txn_receipt_dict, errors=IGNORE)) == 1 + + # STRICT raises an error to be caught + with pytest.raises(InsufficientDataBytes): + returned_log = event_instance.process_receipt(txn_receipt_dict, errors=STRICT) + assert len(returned_log) == 0 diff --git a/web3/contract/base_contract.py b/web3/contract/base_contract.py index 241874d73e..32a424388f 100644 --- a/web3/contract/base_contract.py +++ b/web3/contract/base_contract.py @@ -16,6 +16,9 @@ ) import warnings +from eth_abi.exceptions import ( + InsufficientDataBytes, +) from eth_typing import ( Address, ChecksumAddress, @@ -174,7 +177,13 @@ def _parse_logs( for log in txn_receipt["logs"]: try: rich_log = get_event_data(self.w3.codec, self.abi, log) - except (MismatchedABI, LogTopicError, InvalidEventABI, TypeError) as e: + except ( + MismatchedABI, + LogTopicError, + InvalidEventABI, + TypeError, + InsufficientDataBytes, + ) as e: if errors == DISCARD: continue elif errors == IGNORE: