-
-
Notifications
You must be signed in to change notification settings - Fork 124
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
feat!: allow transaction raise on fail #957
Conversation
cc @NotPeopling2day @fubuloubu @unparalleled-js Hey all, this is just a draft because I have a few questions: Test Environment Txn FailuresI think previously we talked about having a transaction Transaction Field / Pydantic IssuesCurrently I'm running issues with how to actually define this
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we able to avoid adding it to the model if use the same approach that we did for the block_identifier
and state_overrides
kwarg handling?
You can find that in ape.api.providers.Web3Provider
in methods like estimate_gas_cost()
@unparalleled-js yeah I think that would be viable and honestly be a little better in "where" the functionality lives (since really this flag doesn't need to be on a transaction, it just needs to be specified when dealing with transactions) Is there a preferred way to document those kind of kwargs? I see |
For yours, we may want to consider adding to 0.5 API changes since it seems common enough across ecosystems to want to do this. For the other kwargs you mentioned, it got me thinking and this what I landed on so far: I am open to suggestions though, on that PR. |
Yeah, I think so - I gave it a stab in e2c08e0 In the tests Since those functions only take the AccountAPI.call(self, txn: TransactionAPI, send_everything: bool, raise_on_fail: bool)
ProviderAPI.send_transaction(self, txn: TransactionAPI, raise_on_fail: bool) Those two aforementioned tests now show the usage: txn = ...
# non-raising call examples
owner.call(txn, raise_on_fail=False)
provider.send_transaction(txn, raise_on_fail=False)
# raising call examples
owner.call(txn, raise_on_fail=True)
provider.send_transaction(txn, raise_on_fail=True) cc @unparalleled-js @NotPeopling2day |
Rebased off main, some of those commit hashes I just linked might be "old" now haha |
With the kwarg being distributed across a few places, is there a preferred method of how we should handle its default value? I think that perhaps it could be a three-way value and we check inside the logic of the different callsites, for example: def send_transaction(self, ..., raise_on_fail: Optional[bool] = None):
if raise_on_fail is None and os.environ.get("APE_TESTING", False):
raise_on_fail = True cc @unparalleled-js @NotPeopling2day |
Not seeing a way for a contract method to pass this parameter >>> foo.bar(False, sender=dev, raise_on_fail=True)
...
ContractLogicError: Transaction failed. |
@fubuloubu that should be covered by a471f77 unless I'm missing something The test examples define with pytest.raises(TransactionError):
vyper_contract_instance.setNumber(5, sender=owner, gas_limit=100000, raise_on_fail=True) Not passing |
I tried using this with the It did work with |
Yeah I think we'll need corresponding PRs for the different provider plugins since those functions never took |
meant to share when |
overall, I think this might need some good QA over the different circumstances that raise errors |
@helloibis let's setup a call this afternoon and work through some of it |
@fubuloubu is there a short example of what you mean? In |
will have to do a bit of QA on this |
PR is updated and ready for review, I'm getting the corresponding provider plugin PRs ready and adding tests for them Current StateJust added 6f79956 to set the default value back to # By default, gas estimation runs (and can raise) and reverted transactions
# raise an exception (even though they're committed to chain)
>>> receipt = contract.foo(...)
TransactionError
# Setting a gas limit can bypass the estimation, but a reverted transaction will still raise
>>> receipt = contract.foo(..., gas_limit=100000)
TransactionError
# Using `raise_on_fail=False` turns off the receipt raising behavior.
# It currently doesn't affect gas estimation but failed receipts do not raise
>>> receipt = contract.foo(..., raise_on_fail=False)
TransactionError # is gas estimation fails
<ReceiptAPI ...> # if gas estimation passes Future StateLater on it should have the following behavior: # Using `raise_on_fail=False` in the future will also bypass gas estimation. So you can
>>> receipt = contract.foo(..., raise_on_fail=False)
<ReceiptAPI ...> # no gas estimation run, always returns receipt
# Inside ape.reverts(), gas estimation always passes but failed receipts still raise
>>> with ape.reverts():
receipt = contract.foo(...)
TransactionError Because that implementation is different from the kwargs I'm adding, I think it'll be best suited as a separate PR |
Wanted to shout out one difference here, I think in this scenario it should also have the same behavior of bypassing gas estimation (as if receipt = contract.foo(..., raise_on_fail=False)
receipt.raise_for_status() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just did some testing, this is great! I can get failed receipts easily and my projects' tests still pass (with all their revert-based testing etc).
However -- dun dun dun. I noticed this breaks ape-hardhat
and ape-foundry
so we may either have to hold off on merging this to main or do some preparation fixes there first to see if we can mitigate breaking those plugins
Ah yeah, almost forgot about those! I mentioned them earlier but there have been so many comments 😅 will get on those now and make companion PRs that can go in at the same time as this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good
Co-authored-by: Juliya Smith <yingthi@live.com>
Co-authored-by: Juliya Smith <yingthi@live.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -79,6 +84,45 @@ def test_get_receipt_exists_with_timeout(eth_tester_provider, vyper_contract_ins | |||
assert receipt_from_provider.receiver == vyper_contract_instance.address | |||
|
|||
|
|||
def test_get_receipt_without_raising(eth_tester_provider, vyper_contract_instance, owner): | |||
# The Contract raises empty revert when setting number to 5. | |||
receipt_from_invoke = vyper_contract_instance.setNumber( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part of the test might make more sense in test_contract_instance.py
def test_invoke_failing_method_without_raising()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do, I'll take a look at cleaning up some test stuff in the upcoming PR for reverts since that will need to add in testing changes
Moved this to a feature branch since we'll hold til 0.6.0 for the breaking change. This PR should be good to merge now, and here are the accompanying PRs (each with their own feature branch): ApeWorX/ape-hardhat#99 |
What I did
Begin adding in parameters to facilitate explicitly raising on transaction failure. We'll need transactions that fail to deliberately raise an exception for
RevertsContextManager
. That functionality is a dependency for the tracing ticket #251.How I did it
Adding
raise_on_fail: bool
parameter to the following:ReceiptAPI.await_confirmations()
(defaultFalse
)ProviderAPI.get_receipt()
(defaultFalse
)ProviderAPI.send_transaction()
(defaultTrue
)AccountAPI.call()
(defaultTrue
)ImpersonatedAccount.call()
(defaultTrue
)Web3Provider.send_transaction()
(defaultTrue
)ContractTransaction.__call__()
(defaultTrue
)LocalProvider.send_transaction()
(defaultTrue
)How to verify it
Added a test against flipping this parameter when calling the contract function to ensure that the transaction causes an exception rather than just returning a failed receipt
Checklist