-
Notifications
You must be signed in to change notification settings - Fork 443
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
Handle LangError
from instantiate
#1512
Conversation
This commit lets us grab what's in the output buffer after our call to `instantiate`, however we are unable to succesfully decode the `AccountId` from the success case.
acc3f48
to
8796a62
Compare
I accidently introduced this not knowing that the generic `C` was for the return type
Is supposed to help give better error messages if somebody uses a wrong type with the builder
LangError
from instantiate (fails for success case)LangError
from instantiate
Codecov Report
@@ Coverage Diff @@
## master #1512 +/- ##
==========================================
- Coverage 71.67% 71.57% -0.11%
==========================================
Files 204 204
Lines 6320 6321 +1
==========================================
- Hits 4530 4524 -6
- Misses 1790 1797 +7
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
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 the question mark about the handling of the decoding of the LangError
, other than that it looks good.
Err(ext::Error::CalleeReverted) => { | ||
// We don't wrap manually with an extra `Err` like we do in the `Ok` case since the | ||
// buffer already comes back in the form of `Err(LangError)` | ||
let out = scale::Decode::decode(&mut &out_return_value[..])?; |
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.
Couldn't there exist a contract that would revert the contract but return Ok(())
e.g.
::ink::env::return_value::<::ink::ConstructorResult<()>>(
::ink::env::ReturnFlags::new_with_reverted(true),
Ok(()),
);
This could mislead the caller into handling the Ok
case?
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.
Hmm yeah this is a good observation. I've added a test that shows that you can indeed revert from a constructor and continue execution by returning Ok(AccountId)
.
I've also added a quick patch which asserts that the content in the buffer is an error.
I'm not entirely sure what the implications of either case are though...
- In the
Revert + Ok
case, misleading the caller seems like the main reason to do this, but maybe there are legit reasons to do encode anOk
back? I can't think of any though. - In the
Revert + Err
case, the callee can encode the "wrong"LangError
into the output buffer, potentially misleading the caller too, and there's nothing we can do to help there.
Either way it'll be up to the contract developer to make sure they understand that there are risks to calling other contracts.
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.
@athei would like to hear your opinion here
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.
The assumption is that the user is not calling return_value
directly, and if they are they are using it in an ABI compatible way which is either Revert + Err(LangError)
or Revert + Ok(Err(ContracErr))
.
So perhaps we could return an Err(LangError)
here if this ABI is not satisfied, e.g. as mentioned in #1512 (comment)
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.
Okay maybe what we want is something along the lines of
// note changed from `AccountId` to `()`
let out = ink_primitives::ConstructorResult::<()>::decode(
&mut &out_return_value[..],
)?;
match out {
// This branch when a fallible constructor returns `Err`
Ok(()) => Err(ext::Error::CalleeReverted),
/// This branch handles an actual `LangErr`
Err(lang_err) => Ok(Err(lang_err))
}
Co-authored-by: Andrew Jones <ascjones@gmail.com>
Ping me when you're back and we can catch up on this and get it merged |
Edit, sorry I realize this is for a |
Yeah, this is something I wanted to address with #1525 |
09af6a2
to
9a14e21
Compare
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!
The dual method API with fallible
alternatives is a bit clunky, however #1591 provides a solution to that.
This is a follow up to #1504, in which
LangError
s were returned from constructors. Inthat PR we had no way to read the output buffer from
seal_instantiate
and bubble anyinformation back up to the contract caller.
This PR adds support for reading this output buffer for both infallible and fallible
constructors.
Because of type checking problems I've had to add a new set of APIs for handling fallible
constructors. I'm still looking for a way to unify them, as mentioned in this comment.
If you have any ideas for improvements here I'd be happy to hear them.
I've changed the
create_builder
API slightly to be more in-line with thecall_builder
one (i.e removing the generic in favour of a
returns
method).For infallible constructors, the main changes are:
CreateBuilder
now returns aConstructorResult
(introduced in ReturnLangError
s from constructors #1504)try_instantiate
methodFor fallible constructors:
intantiate_fallible
andtry_instantiate_fallible
CreateBuilder
methodsConstructorError
s are only bubbled up in thetry_*
variantUnify fallible and non fallible instantiate methods #1591
ink_env::instantiate_fallible_contract
I've also updated the codegen so that
ContractRef
s can be used to instantiate contracts,as an alternative to the "raw"
CreateBuilder
API.Notes for reviewers:
seal_instantiate
canbe written to:
ink_env::return_value
or by accident) encode erroneous values in there
decoding scenarios
of E2E test "panicked at 'error on call
sign_and_submit_then_watch_default
" #1498(run them locally if you don't believe me 😆)