Skip to content

Commit acc3f48

Browse files
committed
Handle LangError from instantiate (fails for success case)
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.
1 parent b63ef91 commit acc3f48

File tree

9 files changed

+117
-51
lines changed

9 files changed

+117
-51
lines changed

crates/env/src/api.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,16 +319,18 @@ where
319319
/// - If the instantiation process runs out of gas.
320320
/// - If given insufficient endowment.
321321
/// - If the returned account ID failed to decode properly.
322-
pub fn instantiate_contract<E, Args, Salt, C>(
322+
pub fn instantiate_contract<E, Args, Salt, C, R>(
323323
params: &CreateParams<E, Args, Salt, C>,
324-
) -> Result<E::AccountId>
324+
) -> Result<R>
325+
// ) -> Result<E::AccountId>
325326
where
326327
E: Environment,
327328
Args: scale::Encode,
328329
Salt: AsRef<[u8]>,
330+
R: scale::Decode,
329331
{
330332
<EnvInstance as OnInstance>::on_instance(|instance| {
331-
TypedEnvBackend::instantiate_contract::<E, Args, Salt, C>(instance, params)
333+
TypedEnvBackend::instantiate_contract::<E, Args, Salt, C, R>(instance, params)
332334
})
333335
}
334336

crates/env/src/backend.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,14 +439,16 @@ pub trait TypedEnvBackend: EnvBackend {
439439
/// # Note
440440
///
441441
/// For more details visit: [`instantiate_contract`][`crate::instantiate_contract`]
442-
fn instantiate_contract<E, Args, Salt, C>(
442+
fn instantiate_contract<E, Args, Salt, C, R>(
443443
&mut self,
444444
params: &CreateParams<E, Args, Salt, C>,
445-
) -> Result<E::AccountId>
445+
) -> Result<R>
446+
// ) -> Result<E::AccountId>
446447
where
447448
E: Environment,
448449
Args: scale::Encode,
449-
Salt: AsRef<[u8]>;
450+
Salt: AsRef<[u8]>,
451+
R: scale::Decode;
450452

451453
/// Terminates a smart contract.
452454
///

crates/env/src/call/create_builder.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,13 @@ where
116116
E: Environment,
117117
Args: scale::Encode,
118118
Salt: AsRef<[u8]>,
119-
R: FromAccountId<E>,
119+
R: scale::Decode,
120+
// R: FromAccountId<E>,
120121
{
121122
/// Instantiates the contract and returns its account ID back to the caller.
122123
#[inline]
123124
pub fn instantiate(&self) -> Result<R, crate::Error> {
124-
crate::instantiate_contract(self).map(FromAccountId::from_account_id)
125+
crate::instantiate_contract(self) //.map(FromAccountId::from_account_id)
125126
}
126127
}
127128

@@ -135,7 +136,7 @@ where
135136
endowment: Endowment,
136137
exec_input: Args,
137138
salt: Salt,
138-
return_type: ReturnType<R>,
139+
return_type: R,
139140
_phantom: PhantomData<fn() -> E>,
140141
}
141142

@@ -195,11 +196,12 @@ pub fn build_create<E, R>() -> CreateBuilder<
195196
Unset<E::Balance>,
196197
Unset<ExecutionInput<EmptyArgumentList>>,
197198
Unset<state::Salt>,
198-
R,
199+
Unset<ReturnType<R>>,
199200
>
200201
where
201202
E: Environment,
202-
R: FromAccountId<E>,
203+
R: scale::Decode,
204+
// R: FromAccountId<E>,
203205
{
204206
CreateBuilder {
205207
code_hash: Default::default(),
@@ -281,6 +283,34 @@ where
281283
}
282284
}
283285

286+
impl<E, CodeHash, GasLimit, Endowment, Args, Salt>
287+
CreateBuilder<E, CodeHash, GasLimit, Endowment, Args, Salt, Unset<ReturnType<()>>>
288+
where
289+
E: Environment,
290+
{
291+
/// Sets the type of the returned value upon the execution of the call.
292+
///
293+
/// # Note
294+
///
295+
/// Either use `.returns::<()>` to signal that the call does not return a value
296+
/// or use `.returns::<T>` to signal that the call returns a value of type `T`.
297+
#[inline]
298+
pub fn returns<R>(
299+
self,
300+
) -> CreateBuilder<E, CodeHash, GasLimit, Endowment, Args, Salt, Set<ReturnType<R>>>
301+
{
302+
CreateBuilder {
303+
code_hash: self.code_hash,
304+
gas_limit: self.gas_limit,
305+
endowment: self.endowment,
306+
exec_input: self.exec_input,
307+
salt: self.salt,
308+
return_type: Set(Default::default()),
309+
_phantom: Default::default(),
310+
}
311+
}
312+
}
313+
284314
impl<E, CodeHash, GasLimit, Endowment, Salt, R>
285315
CreateBuilder<
286316
E,
@@ -347,7 +377,7 @@ impl<E, GasLimit, Args, Salt, R>
347377
Set<E::Balance>,
348378
Set<ExecutionInput<Args>>,
349379
Set<Salt>,
350-
R,
380+
Set<ReturnType<R>>,
351381
>
352382
where
353383
E: Environment,
@@ -362,7 +392,7 @@ where
362392
endowment: self.endowment.value(),
363393
exec_input: self.exec_input.value(),
364394
salt_bytes: self.salt.value(),
365-
_return_type: self.return_type,
395+
_return_type: Default::default(),
366396
}
367397
}
368398
}
@@ -375,14 +405,15 @@ impl<E, GasLimit, Args, Salt, R>
375405
Set<E::Balance>,
376406
Set<ExecutionInput<Args>>,
377407
Set<Salt>,
378-
R,
408+
Set<ReturnType<R>>,
379409
>
380410
where
381411
E: Environment,
382412
GasLimit: Unwrap<Output = u64>,
383413
Args: scale::Encode,
384414
Salt: AsRef<[u8]>,
385-
R: FromAccountId<E>,
415+
R: scale::Decode,
416+
// R: FromAccountId<E>,
386417
{
387418
/// Instantiates the contract using the given instantiation parameters.
388419
#[inline]

crates/env/src/engine/off_chain/impls.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,14 +469,16 @@ impl TypedEnvBackend for EnvInstance {
469469
)
470470
}
471471

472-
fn instantiate_contract<E, Args, Salt, C>(
472+
fn instantiate_contract<E, Args, Salt, C, R>(
473473
&mut self,
474474
params: &CreateParams<E, Args, Salt, C>,
475-
) -> Result<E::AccountId>
475+
) -> Result<R>
476+
// ) -> Result<E::AccountId>
476477
where
477478
E: Environment,
478479
Args: scale::Encode,
479480
Salt: AsRef<[u8]>,
481+
R: scale::Decode,
480482
{
481483
let _code_hash = params.code_hash();
482484
let _gas_limit = params.gas_limit();

crates/env/src/engine/on_chain/impls.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -479,14 +479,16 @@ impl TypedEnvBackend for EnvInstance {
479479
}
480480
}
481481

482-
fn instantiate_contract<E, Args, Salt, C>(
482+
fn instantiate_contract<E, Args, Salt, C, R>(
483483
&mut self,
484484
params: &CreateParams<E, Args, Salt, C>,
485-
) -> Result<E::AccountId>
485+
) -> Result<R>
486+
// ) -> Result<E::AccountId>
486487
where
487488
E: Environment,
488489
Args: scale::Encode,
489490
Salt: AsRef<[u8]>,
491+
R: scale::Decode,
490492
{
491493
let mut scoped = self.scoped_buffer();
492494
let gas_limit = params.gas_limit();
@@ -503,17 +505,41 @@ impl TypedEnvBackend for EnvInstance {
503505
// This should change in the future but for that we need to add support
504506
// for constructors that may return values.
505507
// This is useful to support fallible constructors for example.
506-
ext::instantiate(
508+
//
509+
// TODO: Support this output buffer?
510+
let instantiate_result = ext::instantiate(
507511
enc_code_hash,
508512
gas_limit,
509513
enc_endowment,
510514
enc_input,
511515
out_address,
512516
out_return_value,
513517
salt,
514-
)?;
515-
let account_id = scale::Decode::decode(&mut &out_address[..])?;
516-
Ok(account_id)
518+
);
519+
520+
match instantiate_result {
521+
Ok(()) => {
522+
// The Ok case always needs to decode into an address
523+
//
524+
// This decodes to an `E::AccountId`
525+
//
526+
// But here I want an `Ok(E::AccountId)`
527+
let account_id = scale::Decode::decode(&mut &out_address[..])?;
528+
Ok(account_id)
529+
530+
// let out = scale::Decode::decode(&mut &out_return_value[..])?;
531+
// Ok(out)
532+
}
533+
Err(ext::Error::CalleeReverted) => {
534+
// This decodes to an `Err(CouldNotReadInput)`
535+
let out = scale::Decode::decode(&mut &out_return_value[..])?;
536+
Ok(out)
537+
}
538+
Err(actual_error) => Err(actual_error.into()),
539+
}
540+
541+
// let account_id = scale::Decode::decode(&mut &out_address[..])?;
542+
// Ok(account_id)
517543
}
518544

519545
fn terminate_contract<E>(&mut self, beneficiary: E::AccountId) -> !

crates/ink/codegen/src/generator/as_dependency/contract_ref.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ impl ContractRef<'_> {
403403
let input_bindings = generator::input_bindings(constructor.inputs());
404404
let input_types = generator::input_types(constructor.inputs());
405405
let arg_list = generator::generate_argument_list(input_types.iter().cloned());
406+
let return_type = constructor.wrapped_output();
406407
quote_spanned!(span =>
407408
#( #attrs )*
408409
#[inline]
@@ -416,9 +417,10 @@ impl ContractRef<'_> {
416417
::ink::env::call::utils::Unset<Balance>,
417418
::ink::env::call::utils::Set<::ink::env::call::ExecutionInput<#arg_list>>,
418419
::ink::env::call::utils::Unset<::ink::env::call::state::Salt>,
419-
Self,
420+
::ink::env::call::utils::Unset<::ink::env::call::utils::ReturnType<#return_type>>,
421+
// Self,
420422
> {
421-
::ink::env::call::build_create::<Environment, Self>()
423+
::ink::env::call::build_create::<Environment, #return_type>()
422424
.exec_input(
423425
::ink::env::call::ExecutionInput::new(
424426
::ink::env::call::Selector::new([ #( #selector_bytes ),* ])

crates/ink/ir/src/ir/item_impl/constructor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ impl Constructor {
236236
let return_type = self
237237
.output()
238238
.map(quote::ToTokens::to_token_stream)
239-
.unwrap_or_else(|| quote::quote! { () });
239+
.unwrap_or_else(|| quote::quote! { Self });
240240

241241
syn::parse_quote! {
242242
::ink::ConstructorResult<#return_type>

crates/ink/src/env_access.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,15 +469,17 @@ where
469469
/// # Note
470470
///
471471
/// For more details visit: [`ink_env::instantiate_contract`]
472-
pub fn instantiate_contract<Args, Salt, C>(
472+
pub fn instantiate_contract<Args, Salt, C, R>(
473473
self,
474474
params: &CreateParams<E, Args, Salt, C>,
475-
) -> Result<E::AccountId>
475+
) -> Result<R>
476+
// ) -> Result<E::AccountId>
476477
where
477478
Args: scale::Encode,
478479
Salt: AsRef<[u8]>,
480+
R: scale::Decode,
479481
{
480-
ink_env::instantiate_contract::<E, Args, Salt, C>(params)
482+
ink_env::instantiate_contract::<E, Args, Salt, C, R>(params)
481483
}
482484

483485
/// Invokes a contract message and returns its result.

examples/lang-err-integration-tests/call-builder/lib.rs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ mod call_builder {
6262
code_hash: Hash,
6363
selector: [u8; 4],
6464
init_value: bool,
65-
) -> Option<AccountId> {
65+
) -> Option<::ink::LangError> {
6666
use ink::env::{
6767
call::{
6868
build_create,
@@ -74,19 +74,30 @@ mod call_builder {
7474

7575
let result = build_create::<
7676
DefaultEnvironment,
77-
constructors_return_value::ConstructorsReturnValueRef,
77+
_,
78+
// constructors_return_value::ConstructorsReturnValueRef,
7879
>()
7980
.code_hash(code_hash)
8081
.gas_limit(0)
8182
.endowment(0)
8283
.exec_input(ExecutionInput::new(Selector::new(selector)).push_arg(init_value))
8384
.salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF])
85+
.returns::<Result<
86+
constructors_return_value::ConstructorsReturnValueRef,
87+
::ink::LangError,
88+
>>()
8489
.params()
85-
.instantiate();
90+
.instantiate()
91+
.expect("Error from the Contracts pallet.");
92+
::ink::env::debug_println!("Result from `instantiate` {:?}", &result);
8693

87-
// NOTE: Right now we can't handle any `LangError` from `instantiate`, we can only tell
88-
// that our contract reverted (i.e we see error from the Contracts pallet).
89-
result.ok().map(|id| ink::ToAccountId::to_account_id(&id))
94+
match result {
95+
Ok(_) => None,
96+
Err(e @ ink::LangError::CouldNotReadInput) => Some(e),
97+
Err(_) => {
98+
unimplemented!("No other `LangError` variants exist at the moment.")
99+
}
100+
}
90101
}
91102
}
92103

@@ -210,14 +221,8 @@ mod call_builder {
210221
None,
211222
)
212223
.await
213-
.expect("Client failed to call `call_builder::call_instantiate`.")
214-
.value
215-
.expect("Dispatching `call_builder::call_instantiate` failed.");
216-
217-
assert!(
218-
call_result.is_some(),
219-
"Call using valid selector failed, when it should've succeeded."
220-
);
224+
.expect("Calling `call_builder::call_instantiate` failed");
225+
dbg!(&call_result.value);
221226

222227
Ok(())
223228
}
@@ -259,14 +264,8 @@ mod call_builder {
259264
None,
260265
)
261266
.await
262-
.expect("Client failed to call `call_builder::call_instantiate`.")
263-
.value
264-
.expect("Dispatching `call_builder::call_instantiate` failed.");
265-
266-
assert!(
267-
call_result.is_none(),
268-
"Call using invalid selector succeeded, when it should've failed."
269-
);
267+
.expect("Client failed to call `call_builder::call_instantiate`.");
268+
dbg!(&call_result.value);
270269

271270
Ok(())
272271
}

0 commit comments

Comments
 (0)