Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a better filter argument api with EventFilterBuilder #953

Merged
merged 5 commits into from
Sep 20, 2018

Conversation

dylanjw
Copy link
Contributor

@dylanjw dylanjw commented Jul 10, 2018

What was wrong?

Related to Issue #872

The existing filter apis are unable to properly differentiate array arguments and multiple match arguments.

How was it fixed?

This PR introduces a new "filter builder" api, where parameters can be set prior to deploying the filter. example:

filter_builder = myContract.events.myEvent.build_filter()
filter_builder.args['array_of_states'].match_single(("CA", "WA", "TX",))
filter_builder.args['array_of_states'].match_any(("CA", "WA", "TX",), ("MN", "OH",))
filter_builder.fromBlock = 0
filter_bulder.toBlock = "latest"
my_filter = filter_builder.deploy() 

Additionally this PR contains a bug fix to the data argument filters, by replacing the regex mechanism with an abi decoding and direct value comparison. EDIT: Replacing the data_filter_set_function created the need to update the contract.py filter api's, as they are required to pass in the data filter set with the abi type.

Cute Animal Picture

image

@implicitly_identity
def decode_abi_strings(abi_type, data):
if abi_type == 'string':
return abi_type, codecs.decode(data, 'utf8', 'backslashreplace')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im getting various DecodingErrors when using the updated eth_abi package that has the change to return strings as string types.

Likely the string data in these tests are not encodable.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, well feel free to copy in a trace if you want another pair of eyes on it.

BTW, there might be other things besides contract arguments/return values that depend on this decode_abi_strings() method, so it's not clear it should be deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carver I moved this to another PR since it needs it own discussion: #974

@dylanjw dylanjw force-pushed the filter_params branch 4 times, most recently from 0b04593 to 041e2ba Compare July 25, 2018 00:01
web3/contract.py Outdated
if topics is not None:
raise NotImplementedError(
"Directly setting topics is not currently supported. "
"Use the argument_filters parameter instead.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this not implemented error to simplify things, as a temporary measure. The ability to set topics directly should be added back to createFilter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to merge the manually entered and the generated topic arguments together, but I realize that that would yield filter results that are entirely different than adding the results from the two sets of filtered data. e.g. merging (A, B) with (C, D) to get a topic list like ((A, C), (B, D)). The merged topic list would match AB, AD, CB, CD instead of just AC, BD. For this reason, manually entering topics needs to either be disabled, or throw an exception if topics have already been generated.

Copy link
Contributor Author

@dylanjw dylanjw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extend tests to include:

filtering dynamic types: bytes, string, un-fixed arrays

web3/contract.py Outdated
if topics is not None:
raise NotImplementedError(
"Directly setting topics is not currently supported. "
"Use the argument_filters parameter instead.")

This comment was marked as resolved.

@dylanjw dylanjw force-pushed the filter_params branch 3 times, most recently from ebcb41a to f00f03f Compare July 30, 2018 19:27
@dylanjw dylanjw force-pushed the filter_params branch 6 times, most recently from db30ac4 to 57daae3 Compare August 7, 2018 18:39
@dylanjw dylanjw changed the title [WIP] Log filter builder Introduce a better filter argument api with EventFilterBuilder Aug 7, 2018
@dylanjw dylanjw force-pushed the filter_params branch 5 times, most recently from eff2856 to 0b3bb9f Compare August 22, 2018 21:11
@dylanjw dylanjw force-pushed the filter_params branch 2 times, most recently from 7246875 to 18c69b4 Compare August 27, 2018 04:28
@pipermerriam
Copy link
Member

I don't see a problem with raising exceptions in cases where previously failures were silent.

@carver
Copy link
Collaborator

carver commented Aug 27, 2018

I'll summarize with a table

Thanks, that helped a lot! Getting support back for 5 is great 👍

what do you think about leaving the exceptions for the 2 cases that had been failing, but could be fixed.

Totally, if the code was already broken (or failing silently), then raising exceptions is a good option. 👍

Copy link
Collaborator

@carver carver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GTG when CI is green

@dylanjw
Copy link
Contributor Author

dylanjw commented Aug 28, 2018

Hypothesis has found a failing example, when the event array argument has 38 or more elements. Ive set the max number of elements to 35. This is probably a eth-tester issue.

@dylanjw
Copy link
Contributor Author

dylanjw commented Aug 30, 2018

@pipermerriam @carver I made some changes to limit value reset, and limit value setting after a filter has been deployed from a filter builder instance. I did the following to share the deployment state between the EventFilterBuilder object and the child argument objects: cf3f795 Is this an anti-pattern? It feels like an anti-pattern.

self.formatter = formatter
self.event_topic = initialize_event_topics(self.event_abi)
self.args = AttributeDict(
_build_argument_filters_from_event_abi(event_abi, self._deployed_flag))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re:

Is this an anti-pattern? It feels like an anti-pattern.

Yeah, I think so too. Maybe instead of this shared flag, replace the args attribute in deploy(). Something like (pseudocode):

-        self._deployed_flag(True)
+        old_args = self.args
+        self.args = ImmutableArgs(old_args)
+        old_args.clear()  # make it clear that people should not use an old saved copy of args

@dylanjw dylanjw force-pushed the filter_params branch 8 times, most recently from 06d5644 to 63c3cdc Compare September 19, 2018 20:19
- Replace the data filter match function with ABI decoded value compare
function
- Include 'string' type utf-8 conversion in match function.
- Disallow array types and match options in old filter API, as these
remain broken. The array type arg filtering and multiple option arg matching
is provided by EventFilterBuilder api.
@dylanjw dylanjw force-pushed the filter_params branch 2 times, most recently from e7c5479 to a76402b Compare September 19, 2018 23:37
@dylanjw
Copy link
Contributor Author

dylanjw commented Sep 19, 2018

@pipermerriam @carver Do you want to give this a final review? Im just about ready to merge.

Copy link
Collaborator

@carver carver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to squash all the fixup commits.

@@ -45,52 +50,41 @@ def fixed_values(draw):

@st.composite
def array_values(draw):
matching = draw(st.lists(elements=st.binary(min_size=2, max_size=2)))
matching = draw(st.lists(elements=st.binary(min_size=2, max_size=2), max_size=35, min_size=1))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hypothesis has found a failing example, when the event array argument has 38 or more elements. Ive set the max number of elements to 35. This is probably a eth-tester issue.

Did you find out any more about this? Does a filter with 38 elements work on, say, geth --dev?

I hate to have this constraint on the test, until we know what's going on.

Copy link
Contributor Author

@dylanjw dylanjw Sep 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ended up being an issue with insufficient gas. I was thrown off in the beginning because I was getting an eth.exceptions.ValidationError: Insufficient gas error with sufficiently large arrays, but there is a range of lower array lengths that fail to emit the event without raising the ValidationError.

Make function name more accurate
Replace hardcoded topic with deriving function
Speed up tests
Fix breaking change: filter argument options static types
Set upper limit on array event arg tests
Parametrize match_fn test
Block value changes post-deployment
Fix broken _utils imports
Update filter data normalizer for eth-abi v2
Remove eventFilter pytest parameter
Estimate gas for array argument tests
Also fix Web3 import
Copy link
Collaborator

@carver carver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GTG on green tests

@dylanjw dylanjw merged commit cc2b67c into ethereum:master Sep 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants