Skip to content

Commit 4ba0173

Browse files
committed
Add error flags to processReceipt
- Add documentation for event log error flags - Change ValueError to custom error, - Split tests to handle different MismatchedABI cases, and split error flag tests out - Make the warn behavior the fallback
1 parent 2eccbff commit 4ba0173

File tree

13 files changed

+1151
-132
lines changed

13 files changed

+1151
-132
lines changed

docs/contracts.rst

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -718,11 +718,11 @@ For example:
718718
719719
:py:class:`ContractEvent` provides methods to interact with contract events. Positional and keyword arguments supplied to the contract event subclass will be used to find the contract event by signature.
720720

721-
.. py:method:: ContractEvents.myEvent(*args, **kwargs).processReceipt(transaction_receipt)
721+
.. py:method:: ContractEvents.myEvent(*args, **kwargs).processReceipt(transaction_receipt, errors=WARN)
722722
723723
Extracts the pertinent logs from a transaction receipt.
724724

725-
Returns a tuple of :ref:`Event Log Objects <event-log-object>`, emitted from the event (e.g. ``myEvent``),
725+
If there are no errors, ``processReceipt`` returns a tuple of :ref:`Event Log Objects <event-log-object>`, emitted from the event (e.g. ``myEvent``),
726726
with decoded ouput.
727727

728728
.. code-block:: python
@@ -733,6 +733,63 @@ For example:
733733
>>> rich_logs[0]['args']
734734
{'myArg': 12345}
735735
736+
The default ``WARN`` flag logs a warning to the console if the log has errors, and the log that raised the warning will be discarded. Any logs that didn't encounter errors during processing will be returned.
737+
There are also a few other flags available:
738+
739+
- ``STRICT`` - stops all processing and raises the error encountered.
740+
- ``IGNORE`` - returns any raw logs that raised an error with an added "errors" field, along with any other logs were able to be processed.
741+
- ``DISCARD`` - silently discards any logs that have errors, and returns processed logs that don't have errors.
742+
- ``WARN`` - logs a warning to the console for the log that has an error, and discards the log. Returns any logs that are able to be processed.
743+
744+
An event log error flag needs to be imported from web3/log.py.
745+
746+
.. code-block:: python
747+
748+
>>> from web3.logs import STRICT, IGNORE, DISCARD, WARN
749+
750+
>>> tx_hash = contract.functions.myFunction(12345).transact({'to':contract_address})
751+
>>> tx_receipt = w3.eth.getTransactionReceipt(tx_hash)
752+
>>> returned_logs = contract.events.myEvent().processReceipt(tx_receipt, errors=IGNORE)
753+
>>> assert returned_logs[0] == tx_receipt['logs'][0]
754+
True
755+
>>> returned_logs = contract.events.myEvent().processReceipt(tx_receipt, errors=DISCARD)
756+
>>> assert returned_logs == ()
757+
True
758+
759+
760+
.. _event-log-object:
761+
762+
Event Log Object
763+
~~~~~~~~~~~~~~~~
764+
765+
The Event Log Object is a python dictionary with the following keys:
766+
767+
* ``args``: Dictionary - The arguments coming from the event.
768+
* ``event``: String - The event name.
769+
* ``logIndex``: Number - integer of the log index position in the block.
770+
* ``transactionIndex``: Number - integer of the transactions index position
771+
log was created from.
772+
* ``transactionHash``: String, 32 Bytes - hash of the transactions this log
773+
was created from.
774+
* ``address``: String, 32 Bytes - address from which this log originated.
775+
* ``blockHash``: String, 32 Bytes - hash of the block where this log was
776+
in. null when it's pending.
777+
* ``blockNumber``: Number - the block number where this log was in. null
778+
when it's pending.
779+
780+
781+
.. code-block:: python
782+
783+
>>> transfer_filter = my_token_contract.eventFilter('Transfer', {'filter': {'_from': '0xdc3a9db694bcdd55ebae4a89b22ac6d12b3f0c24'}})
784+
>>> transfer_filter.get_new_entries()
785+
[...] # array of Event Log Objects that match the filter.
786+
# wait a while...
787+
>>> transfer_filter.get_new_entries()
788+
[...] # new events since the last call
789+
>>> transfer_filter.get_all_entries()
790+
[...] # all events that match the filter.
791+
792+
736793
Utils
737794
-----
738795

tests/core/contracts/conftest.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66
event_signature_to_log_topic,
77
)
88

9+
from web3._utils.module_testing.event_contract import (
10+
EVNT_CONTRACT_ABI,
11+
EVNT_CONTRACT_CODE,
12+
EVNT_CONTRACT_RUNTIME,
13+
)
14+
from web3._utils.module_testing.indexed_event_contract import (
15+
IND_EVENT_CONTRACT_ABI,
16+
IND_EVENT_CONTRACT_CODE,
17+
IND_EVENT_CONTRACT_RUNTIME,
18+
)
19+
920
CONTRACT_NESTED_TUPLE_SOURCE = """
1021
pragma solidity >=0.4.19 <0.6.0;
1122
pragma experimental ABIEncoderV2;
@@ -402,6 +413,121 @@ def emitter(web3_empty, Emitter, wait_for_transaction, wait_for_block, address_c
402413
return emitter_contract
403414

404415

416+
@pytest.fixture()
417+
def EVENT_CONTRACT_CODE():
418+
return EVNT_CONTRACT_CODE
419+
420+
421+
@pytest.fixture()
422+
def EVENT_CONTRACT_RUNTIME():
423+
return EVNT_CONTRACT_RUNTIME
424+
425+
426+
@pytest.fixture()
427+
def EVENT_CONTRACT_ABI():
428+
return EVNT_CONTRACT_ABI
429+
430+
431+
@pytest.fixture()
432+
def EVENT_CONTRACT(
433+
EVENT_CONTRACT_CODE,
434+
EVENT_CONTRACT_RUNTIME,
435+
EVENT_CONTRACT_ABI):
436+
return {
437+
'bytecode': EVENT_CONTRACT_CODE,
438+
'bytecode_runtime': EVENT_CONTRACT_RUNTIME,
439+
'abi': EVENT_CONTRACT_ABI,
440+
}
441+
442+
443+
@pytest.fixture()
444+
def EventContract(web3_empty, EVENT_CONTRACT):
445+
web3 = web3_empty
446+
return web3.eth.contract(**EVENT_CONTRACT)
447+
448+
449+
@pytest.fixture()
450+
def event_contract(
451+
web3_empty,
452+
EventContract,
453+
wait_for_transaction,
454+
wait_for_block,
455+
address_conversion_func):
456+
457+
web3 = web3_empty
458+
459+
wait_for_block(web3)
460+
deploy_txn_hash = EventContract.constructor().transact({
461+
'from': web3.eth.coinbase, 'gas': 1000000
462+
})
463+
deploy_receipt = wait_for_transaction(web3, deploy_txn_hash)
464+
contract_address = address_conversion_func(deploy_receipt['contractAddress'])
465+
466+
bytecode = web3.eth.getCode(contract_address)
467+
assert bytecode == EventContract.bytecode_runtime
468+
event_contract = EventContract(address=contract_address)
469+
assert event_contract.address == contract_address
470+
return event_contract
471+
472+
473+
@pytest.fixture()
474+
def INDEXED_EVENT_CONTRACT_CODE():
475+
return IND_EVENT_CONTRACT_CODE
476+
477+
478+
@pytest.fixture()
479+
def INDEXED_EVENT_CONTRACT_RUNTIME():
480+
return IND_EVENT_CONTRACT_RUNTIME
481+
482+
483+
@pytest.fixture()
484+
def INDEXED_EVENT_CONTRACT_ABI():
485+
return IND_EVENT_CONTRACT_ABI
486+
487+
488+
@pytest.fixture()
489+
def INDEXED_EVENT_CONTRACT(
490+
INDEXED_EVENT_CONTRACT_CODE,
491+
INDEXED_EVENT_CONTRACT_RUNTIME,
492+
INDEXED_EVENT_CONTRACT_ABI):
493+
return {
494+
'bytecode': INDEXED_EVENT_CONTRACT_CODE,
495+
'bytecode_runtime': INDEXED_EVENT_CONTRACT_RUNTIME,
496+
'abi': INDEXED_EVENT_CONTRACT_ABI,
497+
}
498+
499+
500+
@pytest.fixture()
501+
def IndexedEventContract(web3_empty, INDEXED_EVENT_CONTRACT):
502+
web3 = web3_empty
503+
return web3.eth.contract(**INDEXED_EVENT_CONTRACT)
504+
505+
506+
@pytest.fixture()
507+
def indexed_event(
508+
web3_empty,
509+
IndexedEventContract,
510+
wait_for_transaction,
511+
wait_for_block,
512+
address_conversion_func):
513+
514+
web3 = web3_empty
515+
516+
wait_for_block(web3)
517+
deploy_txn_hash = IndexedEventContract.constructor().transact({
518+
'from': web3.eth.coinbase,
519+
'gas': 1000000
520+
})
521+
deploy_receipt = wait_for_transaction(web3, deploy_txn_hash)
522+
contract_address = address_conversion_func(deploy_receipt['contractAddress'])
523+
524+
bytecode = web3.eth.getCode(contract_address)
525+
assert bytecode == IndexedEventContract.bytecode_runtime
526+
indexed_event_contract = IndexedEventContract(address=contract_address)
527+
assert indexed_event_contract.address == contract_address
528+
return indexed_event_contract
529+
530+
405531
CONTRACT_ARRAYS_SOURCE = """
406532
contract ArraysContract {
407533
@@ -698,6 +824,7 @@ class LogFunctions:
698824
LogDoubleWithIndex = 9
699825
LogTripleWithIndex = 10
700826
LogQuadrupleWithIndex = 11
827+
LogBytes = 12
701828

702829

703830
@pytest.fixture()

tests/core/contracts/contract_sources/Emitter.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,28 @@ contract Emitter {
7575
else if (which == WhichEvent.LogQuadrupleWithIndex) emit LogQuadrupleWithIndex(arg0, arg1, arg2, arg3);
7676
else revert("Didn't match any allowable event index");
7777
}
78+
7879
function logDynamicArgs(string arg0, string arg1) public {
7980
emit LogDynamicArgs(arg0, arg1);
8081
}
82+
8183
function logListArgs(bytes2[] arg0, bytes2[] arg1) public {
8284
emit LogListArgs(arg0, arg1);
8385
}
86+
8487
function logAddressIndexedArgs(address arg0, address arg1) public {
8588
emit LogAddressIndexed(arg0, arg1);
8689
}
90+
8791
function logAddressNotIndexedArgs(address arg0, address arg1) public {
8892
emit LogAddressNotIndexed(arg0, arg1);
8993
}
94+
95+
function logBytes(bytes v) public {
96+
emit LogBytes(v);
97+
}
98+
99+
function logString(string v) public {
100+
emit LogString(v);
101+
}
90102
}

0 commit comments

Comments
 (0)