Skip to content

Commit 7723030

Browse files
DefiDebaucheryPaul Robinson
and
Paul Robinson
authored
asyncify eth.get_logs (#2310)
* asyncify eth.get_logs * factor out `assert_contains_log` function Co-authored-by: Paul Robinson <paul@pacrob.com>
1 parent c85b7d9 commit 7723030

File tree

4 files changed

+190
-22
lines changed

4 files changed

+190
-22
lines changed

docs/providers.rst

+1
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ Eth
420420
- :meth:`web3.eth.get_balance() <web3.eth.Eth.get_balance>`
421421
- :meth:`web3.eth.get_block() <web3.eth.Eth.get_block>`
422422
- :meth:`web3.eth.get_code() <web3.eth.Eth.get_code>`
423+
- :meth:`web3.eth.get_logs() <web3.eth.Eth.get_logs>`
423424
- :meth:`web3.eth.get_raw_transaction() <web3.eth.Eth.get_raw_transaction>`
424425
- :meth:`web3.eth.get_raw_transaction_by_block() <web3.eth.Eth.get_raw_transaction_by_block>`
425426
- :meth:`web3.eth.get_transaction() <web3.eth.Eth.get_transaction>`

newsfragments/2310.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add async `eth.get_logs` method

web3/_utils/module_testing/eth_module.py

+177-22
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ def mine_pending_block(web3: "Web3") -> None:
8383
web3.geth.miner.stop() # type: ignore
8484

8585

86+
def _assert_contains_log(
87+
result: Sequence[LogReceipt],
88+
block_with_txn_with_log: BlockData,
89+
emitter_contract_address: ChecksumAddress,
90+
txn_hash_with_log: HexStr,
91+
) -> None:
92+
assert len(result) == 1
93+
log_entry = result[0]
94+
assert log_entry['blockNumber'] == block_with_txn_with_log['number']
95+
assert log_entry['blockHash'] == block_with_txn_with_log['hash']
96+
assert log_entry['logIndex'] == 0
97+
assert is_same_address(log_entry['address'], emitter_contract_address)
98+
assert log_entry['transactionIndex'] == 0
99+
assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)
100+
101+
86102
class AsyncEthModuleTest:
87103
@pytest.mark.asyncio
88104
async def test_eth_gas_price(self, async_w3: "Web3") -> None:
@@ -848,6 +864,143 @@ async def test_async_eth_accounts(self, async_w3: "Web3") -> None:
848864
))
849865
assert await async_w3.eth.coinbase in accounts # type: ignore
850866

867+
@pytest.mark.asyncio
868+
async def test_async_eth_get_logs_without_logs(
869+
self, async_w3: "Web3", block_with_txn_with_log: BlockData
870+
) -> None:
871+
# Test with block range
872+
873+
filter_params: FilterParams = {
874+
"fromBlock": BlockNumber(0),
875+
"toBlock": BlockNumber(block_with_txn_with_log['number'] - 1),
876+
}
877+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
878+
assert len(result) == 0
879+
880+
# the range is wrong
881+
filter_params = {
882+
"fromBlock": block_with_txn_with_log['number'],
883+
"toBlock": BlockNumber(block_with_txn_with_log['number'] - 1),
884+
}
885+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
886+
assert len(result) == 0
887+
888+
# Test with `address`
889+
890+
# filter with other address
891+
filter_params = {
892+
"fromBlock": BlockNumber(0),
893+
"address": UNKNOWN_ADDRESS,
894+
}
895+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
896+
assert len(result) == 0
897+
898+
# Test with multiple `address`
899+
900+
# filter with other address
901+
filter_params = {
902+
"fromBlock": BlockNumber(0),
903+
"address": [UNKNOWN_ADDRESS, UNKNOWN_ADDRESS],
904+
}
905+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
906+
assert len(result) == 0
907+
908+
@pytest.mark.asyncio
909+
async def test_async_eth_get_logs_with_logs(
910+
self,
911+
async_w3: "Web3",
912+
block_with_txn_with_log: BlockData,
913+
emitter_contract_address: ChecksumAddress,
914+
txn_hash_with_log: HexStr,
915+
) -> None:
916+
917+
# Test with block range
918+
919+
# the range includes the block where the log resides in
920+
filter_params: FilterParams = {
921+
"fromBlock": block_with_txn_with_log['number'],
922+
"toBlock": block_with_txn_with_log['number'],
923+
}
924+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
925+
_assert_contains_log(
926+
result,
927+
block_with_txn_with_log,
928+
emitter_contract_address,
929+
txn_hash_with_log
930+
)
931+
932+
# specify only `from_block`. by default `to_block` should be 'latest'
933+
filter_params = {
934+
"fromBlock": BlockNumber(0),
935+
}
936+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
937+
_assert_contains_log(
938+
result,
939+
block_with_txn_with_log,
940+
emitter_contract_address,
941+
txn_hash_with_log
942+
)
943+
944+
# Test with `address`
945+
946+
# filter with emitter_contract.address
947+
filter_params = {
948+
"fromBlock": BlockNumber(0),
949+
"address": emitter_contract_address,
950+
}
951+
952+
@pytest.mark.asyncio
953+
async def test_async_eth_get_logs_with_logs_topic_args(
954+
self,
955+
async_w3: "Web3",
956+
block_with_txn_with_log: BlockData,
957+
emitter_contract_address: ChecksumAddress,
958+
txn_hash_with_log: HexStr,
959+
) -> None:
960+
961+
# Test with None event sig
962+
963+
filter_params: FilterParams = {
964+
"fromBlock": BlockNumber(0),
965+
"topics": [
966+
None,
967+
HexStr('0x000000000000000000000000000000000000000000000000000000000000d431')],
968+
}
969+
970+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
971+
_assert_contains_log(
972+
result,
973+
block_with_txn_with_log,
974+
emitter_contract_address,
975+
txn_hash_with_log
976+
)
977+
978+
# Test with None indexed arg
979+
filter_params = {
980+
"fromBlock": BlockNumber(0),
981+
"topics": [
982+
HexStr('0x057bc32826fbe161da1c110afcdcae7c109a8b69149f727fc37a603c60ef94ca'),
983+
None],
984+
}
985+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
986+
_assert_contains_log(
987+
result,
988+
block_with_txn_with_log,
989+
emitter_contract_address,
990+
txn_hash_with_log
991+
)
992+
993+
@pytest.mark.asyncio
994+
async def test_async_eth_get_logs_with_logs_none_topic_args(self, async_w3: "Web3") -> None:
995+
# Test with None overflowing
996+
filter_params: FilterParams = {
997+
"fromBlock": BlockNumber(0),
998+
"topics": [None, None, None],
999+
}
1000+
1001+
result = await async_w3.eth.get_logs(filter_params) # type: ignore
1002+
assert len(result) == 0
1003+
8511004
def test_async_provider_default_account(
8521005
self,
8531006
async_w3: "Web3",
@@ -2718,15 +2871,6 @@ def test_eth_get_logs_with_logs(
27182871
emitter_contract_address: ChecksumAddress,
27192872
txn_hash_with_log: HexStr,
27202873
) -> None:
2721-
def assert_contains_log(result: Sequence[LogReceipt]) -> None:
2722-
assert len(result) == 1
2723-
log_entry = result[0]
2724-
assert log_entry['blockNumber'] == block_with_txn_with_log['number']
2725-
assert log_entry['blockHash'] == block_with_txn_with_log['hash']
2726-
assert log_entry['logIndex'] == 0
2727-
assert is_same_address(log_entry['address'], emitter_contract_address)
2728-
assert log_entry['transactionIndex'] == 0
2729-
assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)
27302874

27312875
# Test with block range
27322876

@@ -2736,14 +2880,24 @@ def assert_contains_log(result: Sequence[LogReceipt]) -> None:
27362880
"toBlock": block_with_txn_with_log['number'],
27372881
}
27382882
result = web3.eth.get_logs(filter_params)
2739-
assert_contains_log(result)
2883+
_assert_contains_log(
2884+
result,
2885+
block_with_txn_with_log,
2886+
emitter_contract_address,
2887+
txn_hash_with_log
2888+
)
27402889

27412890
# specify only `from_block`. by default `to_block` should be 'latest'
27422891
filter_params = {
27432892
"fromBlock": BlockNumber(0),
27442893
}
27452894
result = web3.eth.get_logs(filter_params)
2746-
assert_contains_log(result)
2895+
_assert_contains_log(
2896+
result,
2897+
block_with_txn_with_log,
2898+
emitter_contract_address,
2899+
txn_hash_with_log
2900+
)
27472901

27482902
# Test with `address`
27492903

@@ -2760,15 +2914,6 @@ def test_eth_get_logs_with_logs_topic_args(
27602914
emitter_contract_address: ChecksumAddress,
27612915
txn_hash_with_log: HexStr,
27622916
) -> None:
2763-
def assert_contains_log(result: Sequence[LogReceipt]) -> None:
2764-
assert len(result) == 1
2765-
log_entry = result[0]
2766-
assert log_entry['blockNumber'] == block_with_txn_with_log['number']
2767-
assert log_entry['blockHash'] == block_with_txn_with_log['hash']
2768-
assert log_entry['logIndex'] == 0
2769-
assert is_same_address(log_entry['address'], emitter_contract_address)
2770-
assert log_entry['transactionIndex'] == 0
2771-
assert log_entry['transactionHash'] == HexBytes(txn_hash_with_log)
27722917

27732918
# Test with None event sig
27742919

@@ -2780,7 +2925,12 @@ def assert_contains_log(result: Sequence[LogReceipt]) -> None:
27802925
}
27812926

27822927
result = web3.eth.get_logs(filter_params)
2783-
assert_contains_log(result)
2928+
_assert_contains_log(
2929+
result,
2930+
block_with_txn_with_log,
2931+
emitter_contract_address,
2932+
txn_hash_with_log
2933+
)
27842934

27852935
# Test with None indexed arg
27862936
filter_params = {
@@ -2790,7 +2940,12 @@ def assert_contains_log(result: Sequence[LogReceipt]) -> None:
27902940
None],
27912941
}
27922942
result = web3.eth.get_logs(filter_params)
2793-
assert_contains_log(result)
2943+
_assert_contains_log(
2944+
result,
2945+
block_with_txn_with_log,
2946+
emitter_contract_address,
2947+
txn_hash_with_log
2948+
)
27942949

27952950
def test_eth_get_logs_with_logs_none_topic_args(self, web3: "Web3") -> None:
27962951
# Test with None overflowing

web3/eth.py

+11
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,17 @@ async def get_code(
436436
) -> HexBytes:
437437
return await self._get_code(account, block_identifier)
438438

439+
_get_logs: Method[Callable[[FilterParams], Awaitable[List[LogReceipt]]]] = Method(
440+
RPC.eth_getLogs,
441+
mungers=[default_root_munger]
442+
)
443+
444+
async def get_logs(
445+
self,
446+
filter_params: FilterParams,
447+
) -> List[LogReceipt]:
448+
return await self._get_logs(filter_params)
449+
439450
_get_transaction_count: Method[Callable[..., Awaitable[Nonce]]] = Method(
440451
RPC.eth_getTransactionCount,
441452
mungers=[BaseEth.block_id_munger],

0 commit comments

Comments
 (0)