1use cfg_if::cfg_if;
16#[cfg(feature = "unstable-hostfn")]
17use ink_primitives::ConstructorResult;
18#[cfg(feature = "unstable-hostfn")]
19use pallet_revive_uapi::ReturnErrorCode;
20
21use crate::backend::{
22 EnvBackend,
23 TypedEnvBackend,
24};
25#[cfg(feature = "unstable-hostfn")]
26use crate::{
27 call::{
28 utils::{
29 ConstructorError,
30 DecodeConstructorError,
31 },
32 ConstructorReturnType,
33 FromAddr,
34 },
35 Error,
36 Result as EnvResult,
37};
38
39macro_rules! array_mut_ref {
48 ($arr:expr, $offset:expr, $len:expr) => {{
49 {
50 fn as_array<T>(slice: &mut [T]) -> &mut [T; $len] {
51 slice.try_into().unwrap()
52 }
53 let offset: usize = $offset;
54 let slice = &mut $arr[offset..offset.checked_add($len).unwrap()];
55 as_array(slice)
56 }
57 }};
58}
59
60pub trait OnInstance: EnvBackend + TypedEnvBackend {
61 fn on_instance<F, R>(f: F) -> R
62 where
63 F: FnOnce(&mut Self) -> R;
64}
65
66cfg_if! {
67 if #[cfg(not(feature = "std"))] {
68 mod on_chain;
69 pub use self::on_chain::EnvInstance;
70 } else {
71 pub mod off_chain;
72 pub use self::off_chain::EnvInstance;
73 }
74}
75
76#[cfg_attr(all(feature = "std", not(test)), allow(dead_code))]
78#[cfg(feature = "unstable-hostfn")] pub(crate) fn decode_instantiate_result<I, ContractRef, R, Abi>(
80 instantiate_result: EnvResult<()>,
81 out_address: &mut I,
82 out_return_value: &[u8],
83) -> EnvResult<ConstructorResult<<R as ConstructorReturnType<ContractRef, Abi>>::Output>>
84where
85 I: scale::Input,
86 ContractRef: FromAddr,
87 R: ConstructorReturnType<ContractRef, Abi>,
88{
89 match instantiate_result {
90 Ok(()) => {
91 let addr = scale::Decode::decode(out_address)?;
92 let contract_ref = <ContractRef as FromAddr>::from_addr(addr);
93 let output = <R as ConstructorReturnType<ContractRef, Abi>>::ok(contract_ref);
94 Ok(Ok(output))
95 }
96 Err(Error::ReturnError(ReturnErrorCode::CalleeReverted)) => {
97 decode_instantiate_err::<ContractRef, R, Abi>(out_return_value)
98 }
99 Err(actual_error) => Err(actual_error),
100 }
101}
102
103#[cfg_attr(all(feature = "std", not(test)), allow(dead_code))]
104#[cfg(feature = "unstable-hostfn")] fn decode_instantiate_err<ContractRef, R, Abi>(
106 out_return_value: &[u8],
107) -> EnvResult<ConstructorResult<<R as ConstructorReturnType<ContractRef, Abi>>::Output>>
108where
109 ContractRef: FromAddr,
110 R: ConstructorReturnType<ContractRef, Abi>,
111{
112 let decoded_error =
113 <<R as ConstructorReturnType<ContractRef, Abi>>::Error as DecodeConstructorError<
114 Abi,
115 >>::decode_error_output(out_return_value);
116 match decoded_error {
117 ConstructorError::Contract(contract_err) => {
118 let error_output =
119 <R as ConstructorReturnType<ContractRef, Abi>>::err(contract_err);
120 match error_output {
121 Some(output) => Ok(Ok(output)),
122 None => {
123 Err(Error::ReturnError(ReturnErrorCode::CalleeReverted))
127 }
128 }
129 }
130 ConstructorError::Lang(lang_err) => Ok(Err(lang_err)),
131 ConstructorError::Env(env_err) => Err(env_err),
132 }
133}
134
135#[cfg(test)]
136mod decode_instantiate_result_tests {
137 use super::*;
138 use crate::DefaultEnvironment;
139 use ink_primitives::Address;
140 use scale::Encode;
141
142 type ContractResult<T, E> = Result<T, E>;
144
145 #[derive(Debug, PartialEq, scale::Encode, scale::Decode)]
146 struct ContractError(String);
147
148 #[allow(dead_code)]
150 #[derive(Debug, PartialEq)]
151 struct TestContractRef(Address);
152
153 impl crate::ContractEnv for TestContractRef {
154 type Env = DefaultEnvironment;
155 }
156
157 impl FromAddr for TestContractRef {
158 fn from_addr(addr: Address) -> Self {
159 Self(addr)
160 }
161 }
162
163 fn encode_and_decode_return_value(
164 return_value: ConstructorResult<Result<(), ContractError>>,
165 ) -> EnvResult<ConstructorResult<Result<TestContractRef, ContractError>>> {
166 let out_address = Vec::new();
167 let encoded_return_value = return_value.encode();
168 decode_return_value_fallible(&mut &out_address[..], &encoded_return_value[..])
169 }
170
171 fn decode_return_value_fallible<I: scale::Input>(
172 out_address: &mut I,
173 out_return_value: &[u8],
174 ) -> EnvResult<ConstructorResult<Result<TestContractRef, ContractError>>> {
175 decode_instantiate_result::<
176 I,
177 TestContractRef,
178 Result<TestContractRef, ContractError>,
179 ink_primitives::abi::Ink,
180 >(
181 Err(ReturnErrorCode::CalleeReverted.into()),
182 out_address,
183 out_return_value,
184 )
185 }
186
187 #[test]
188 fn revert_branch_rejects_valid_output_buffer_with_success_case() {
189 let return_value = ConstructorResult::Ok(ContractResult::Ok(()));
190
191 let decoded_result = encode_and_decode_return_value(return_value);
192
193 let expected_error: EnvResult<
194 ConstructorResult<Result<TestContractRef, ContractError>>,
195 > = EnvResult::Err(crate::Error::Decode(
196 "The callee reverted, but did not encode an error in the output buffer."
197 .into(),
198 ));
199 assert_eq!(decoded_result, expected_error);
200 }
201
202 #[test]
203 fn successful_dispatch_with_error_from_contract_constructor() {
204 let return_value = ConstructorResult::Ok(ContractResult::Err(ContractError(
205 "Contract's constructor failed.".to_owned(),
206 )));
207
208 let decoded_result = encode_and_decode_return_value(return_value);
209
210 assert!(matches!(
211 decoded_result,
212 EnvResult::Ok(ConstructorResult::Ok(ContractResult::Err(ContractError(_))))
213 ))
214 }
215
216 #[test]
217 fn dispatch_error_gets_decoded_correctly() {
218 let return_value =
219 ConstructorResult::Err(ink_primitives::LangError::CouldNotReadInput);
220
221 let decoded_result = encode_and_decode_return_value(return_value);
222
223 assert!(matches!(
224 decoded_result,
225 EnvResult::Ok(ConstructorResult::Err(
226 ink_primitives::LangError::CouldNotReadInput
227 ))
228 ))
229 }
230
231 #[test]
232 fn invalid_bytes_in_output_buffer_fail_decoding() {
233 let out_address = Vec::new();
234 let invalid_encoded_return_value = [69];
235
236 let decoded_result = decode_return_value_fallible(
237 &mut &out_address[..],
238 &invalid_encoded_return_value[..],
239 );
240
241 assert!(matches!(decoded_result, Err(crate::Error::Decode(_))))
242 }
243}