From d178f2ef3ced832bcbf032980de2a64364ab122e Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Thu, 8 Feb 2024 14:59:38 -0700 Subject: [PATCH 1/5] Sort events by logIndex --- web3/contract/contract.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web3/contract/contract.py b/web3/contract/contract.py index c9e4ac8a7c..62a3fe1ad7 100644 --- a/web3/contract/contract.py +++ b/web3/contract/contract.py @@ -192,7 +192,8 @@ def get_logs( all_event_logs, argument_filters, ) - return filtered_logs + sorted_logs = sorted(filtered_logs, key=lambda e: e["logIndex"]) + return sorted_logs @combomethod def create_filter( From 13e56786e2f5124a91d103fb7edab16f86fb3f0e Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Thu, 8 Feb 2024 16:14:18 -0700 Subject: [PATCH 2/5] Test for contract event logs to ensure sort order --- tests/conftest.py | 8 ++- .../contracts/test_extracting_event_data.py | 68 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6a4b502867..730ddb0053 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -46,9 +46,10 @@ def emitter_contract_data(): return EMITTER_CONTRACT_DATA +# This class defines events for the EmitterContract and are used to construct +# a fixture for contract event logs. Parameterized tests that utilize an `emitter` +# contract fixture will use this data. class LogFunctions: - # These appear to be for a very specific test and this doesn't need to be updated - # for every event in the emitter contract. That ends up breaking that test. LogAnonymous = 0 LogNoArguments = 1 LogSingleArg = 2 @@ -74,6 +75,9 @@ def emitter_contract_event_ids(): return LogFunctions +# This class defines topics for the EmitterContract and are used to construct +# a fixture for contract event log topics. Parameterized tests that utilize +# an `emitter` contract fixture will use this data. class LogTopics: LogAnonymous = event_signature_to_log_topic("LogAnonymous()") LogNoArguments = event_signature_to_log_topic("LogNoArguments()") diff --git a/tests/core/contracts/test_extracting_event_data.py b/tests/core/contracts/test_extracting_event_data.py index 07e113dbf4..47be66edb8 100644 --- a/tests/core/contracts/test_extracting_event_data.py +++ b/tests/core/contracts/test_extracting_event_data.py @@ -331,6 +331,74 @@ def test_argument_extraction_strict_bytes_types( assert event_data["event"] == "LogListArgs" +def test_contract_event_get_logs_sorted_by_log_index(w3, emitter, request_mocker): + get_logs_response = [ + { + "type": "mined", + "logIndex": 10, + "transactionIndex": 0, + "transactionHash": "0xaef7f312d863780b861d8c38984b2a33f77e9508810735e2b042143f7f189f83", # noqa: E501 + "blockHash": "0x2200ec3324fdaca4ee2f4629489d2d06fb28108dae61b63b84ef39702e2b64e7", # noqa: E501 + "blockNumber": 3, + "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", + "data": "0x", + "topics": [ + "0x1e86022f78f8d04f8e3dfd13a2bdb280403e6632877c0dbee5e4eeb259908a5c" + ], + }, + { + "type": "mined", + "logIndex": 0, + "transactionIndex": 0, + "transactionHash": "0x61e57bb1b5af14ca1b0964a84fb640bf39927961f26311a6450475a749e00cbb", # noqa: E501 + "blockHash": "0x73dd9a3b0f581689ebd67adea0debe05672a334c723379dc506fb71a666c1754", # noqa: E501 + "blockNumber": 4, + "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", + "data": "0x", + "topics": [ + "0x1e86022f78f8d04f8e3dfd13a2bdb280403e6632877c0dbee5e4eeb259908a5c" + ], + }, + { + "type": "mined", + "logIndex": 123, + "transactionIndex": 0, + "transactionHash": "0x61e57bb1b5af14ca1b0964a84fb640bf39927961f26311a6450475a749e00cbb", # noqa: E501 + "blockHash": "0x73dd9a3b0f581689ebd67adea0debe05672a334c723379dc506fb71a666c1754", # noqa: E501 + "blockNumber": 4, + "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", + "data": "0x", + "topics": [ + "0x1e86022f78f8d04f8e3dfd13a2bdb280403e6632877c0dbee5e4eeb259908a5c" + ], + }, + { + "type": "mined", + "logIndex": 54, + "transactionIndex": 0, + "transactionHash": "0x61e57bb1b5af14ca1b0964a84fb640bf39927961f26311a6450475a749e00cbb", # noqa: E501 + "blockHash": "0x73dd9a3b0f581689ebd67adea0debe05672a334c723379dc506fb71a666c1754", # noqa: E501 + "blockNumber": 4, + "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", + "data": "0x", + "topics": [ + "0x1e86022f78f8d04f8e3dfd13a2bdb280403e6632877c0dbee5e4eeb259908a5c" + ], + }, + ] + + with request_mocker(w3, mock_results={"eth_getLogs": get_logs_response}): + logs = emitter.events.LogNoArguments().get_logs() + + sorted_logs = sorted( + emitter.events.LogNoArguments().get_logs(), + key=lambda l: l["logIndex"], + ) + + assert len(logs) == 4 + assert logs == sorted_logs + + @pytest.mark.parametrize( "contract_fn,event_name,call_args,expected_args,warning_msg,process_receipt", ( From eff80fc3f01559ad617c0e7cd7a3c27f69198924 Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Fri, 9 Feb 2024 15:04:28 -0700 Subject: [PATCH 3/5] Add doc for get_logs sort order --- docs/web3.contract.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/web3.contract.rst b/docs/web3.contract.rst index ee836ca349..f5082e29bb 100644 --- a/docs/web3.contract.rst +++ b/docs/web3.contract.rst @@ -944,6 +944,8 @@ For example: Fetches all logs for a given event within the specified block range or block hash. + Returns a list of decoded event logs sorted by ``logIndex``. + ``argument_filters`` is an optional dictionary argument that can be used to filter for logs where the event's argument values match the values provided in the dictionary. The keys must match the event argument names as they exist in the ABI. From 147bf4833c32dfa39710e1460db83d9d1d80c182 Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Fri, 9 Feb 2024 15:34:18 -0700 Subject: [PATCH 4/5] Update sort by block number and log index --- tests/core/contracts/test_extracting_event_data.py | 8 ++++++-- web3/contract/contract.py | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/core/contracts/test_extracting_event_data.py b/tests/core/contracts/test_extracting_event_data.py index 47be66edb8..630a2c0471 100644 --- a/tests/core/contracts/test_extracting_event_data.py +++ b/tests/core/contracts/test_extracting_event_data.py @@ -365,7 +365,7 @@ def test_contract_event_get_logs_sorted_by_log_index(w3, emitter, request_mocker "transactionIndex": 0, "transactionHash": "0x61e57bb1b5af14ca1b0964a84fb640bf39927961f26311a6450475a749e00cbb", # noqa: E501 "blockHash": "0x73dd9a3b0f581689ebd67adea0debe05672a334c723379dc506fb71a666c1754", # noqa: E501 - "blockNumber": 4, + "blockNumber": 1, "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", "data": "0x", "topics": [ @@ -378,7 +378,7 @@ def test_contract_event_get_logs_sorted_by_log_index(w3, emitter, request_mocker "transactionIndex": 0, "transactionHash": "0x61e57bb1b5af14ca1b0964a84fb640bf39927961f26311a6450475a749e00cbb", # noqa: E501 "blockHash": "0x73dd9a3b0f581689ebd67adea0debe05672a334c723379dc506fb71a666c1754", # noqa: E501 - "blockNumber": 4, + "blockNumber": 1, "address": "0xF2E246BB76DF876Cef8b38ae84130F4F55De395b", "data": "0x", "topics": [ @@ -394,6 +394,10 @@ def test_contract_event_get_logs_sorted_by_log_index(w3, emitter, request_mocker emitter.events.LogNoArguments().get_logs(), key=lambda l: l["logIndex"], ) + sorted_logs = sorted( + emitter.events.LogNoArguments().get_logs(), + key=lambda l: l["blockNumber"], + ) assert len(logs) == 4 assert logs == sorted_logs diff --git a/web3/contract/contract.py b/web3/contract/contract.py index 62a3fe1ad7..75dbc34c4d 100644 --- a/web3/contract/contract.py +++ b/web3/contract/contract.py @@ -193,6 +193,7 @@ def get_logs( argument_filters, ) sorted_logs = sorted(filtered_logs, key=lambda e: e["logIndex"]) + sorted_logs = sorted(sorted_logs, key=lambda e: e["blockNumber"]) return sorted_logs @combomethod From 531fb30da072c997c1036b284b5cc0ab8a767f9e Mon Sep 17 00:00:00 2001 From: Stuart Reed Date: Fri, 9 Feb 2024 11:11:18 -0700 Subject: [PATCH 5/5] newsfragment for #3228 --- newsfragments/3228.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/3228.feature.rst diff --git a/newsfragments/3228.feature.rst b/newsfragments/3228.feature.rst new file mode 100644 index 0000000000..8a9b0a9813 --- /dev/null +++ b/newsfragments/3228.feature.rst @@ -0,0 +1 @@ +Contract event ``get_logs`` results sorted by each ``ContractEvent`` ``logIndex``. \ No newline at end of file