Skip to content

Commit 1228905

Browse files
taskoohRobbepop
authored andcommitted
Implement ext_call in ink! (#133)
* import ext_call to trait and add function to generate input_data of ext_call remove #[allow(unused)] from ext_call() implment call_invoke and call_evaluate fix format call_invoke and call_evaluate returns Return<_,CallError> fixed * fix format and change return type of test_env * [core] implement CallError as struct and add call_return field to text_env * fix trivial and remove lang/src/encode_input_data * [core] use map_err while handling Result<>
1 parent 55fb144 commit 1228905

File tree

8 files changed

+202
-7
lines changed

8 files changed

+202
-7
lines changed

core/src/env/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ mod test_env;
4040
pub use api::*;
4141
pub use traits::*;
4242

43-
pub use self::srml::DefaultSrmlTypes;
43+
pub use self::srml::{
44+
CallError,
45+
DefaultSrmlTypes,
46+
};
4447

4548
/// The storage environment implementation that is currently being used.
4649
///

core/src/env/srml/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ mod srml_only;
1919

2020
mod types;
2121

22-
pub use self::types::DefaultSrmlTypes;
22+
pub use self::types::{
23+
CallError,
24+
DefaultSrmlTypes,
25+
};
2326

2427
#[cfg(not(feature = "test-env"))]
2528
pub use self::srml_only::{

core/src/env/srml/srml_only/impls.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use crate::{
1818
env::{
1919
srml::sys,
20+
CallError,
2021
Env,
2122
EnvStorage,
2223
EnvTypes,
@@ -25,7 +26,10 @@ use crate::{
2526
storage::Key,
2627
};
2728
use core::marker::PhantomData;
28-
use scale::Decode;
29+
use scale::{
30+
Decode,
31+
Encode,
32+
};
2933

3034
/// Load the contents of the scratch buffer
3135
fn read_scratch_buffer() -> Vec<u8> {
@@ -160,4 +164,56 @@ where
160164
fn dispatch_raw_call(data: &[u8]) {
161165
unsafe { sys::ext_dispatch_call(data.as_ptr() as u32, data.len() as u32) }
162166
}
167+
168+
fn call_invoke(
169+
callee: <Self as EnvTypes>::AccountId,
170+
gas: u64,
171+
value: <Self as EnvTypes>::Balance,
172+
input_data: &[u8],
173+
) -> Result<(), CallError> {
174+
let callee = callee.encode();
175+
let value = value.encode();
176+
unsafe {
177+
let success = sys::ext_call(
178+
callee.as_ptr() as u32,
179+
callee.len() as u32,
180+
gas,
181+
value.as_ptr() as u32,
182+
value.len() as u32,
183+
input_data.as_ptr() as u32,
184+
input_data.len() as u32,
185+
);
186+
if success == 0 {
187+
Ok(())
188+
} else {
189+
Err(CallError)
190+
}
191+
}
192+
}
193+
194+
fn call_evaluate<U: Decode>(
195+
callee: <Self as EnvTypes>::AccountId,
196+
gas: u64,
197+
value: <Self as EnvTypes>::Balance,
198+
input_data: &[u8],
199+
) -> Result<U, CallError> {
200+
let callee = callee.encode();
201+
let value = value.encode();
202+
unsafe {
203+
let success = sys::ext_call(
204+
callee.as_ptr() as u32,
205+
callee.len() as u32,
206+
gas,
207+
value.as_ptr() as u32,
208+
value.len() as u32,
209+
input_data.as_ptr() as u32,
210+
input_data.len() as u32,
211+
);
212+
if success == 0 {
213+
U::decode(&mut &read_scratch_buffer()[..]).map_err(|_| CallError)
214+
} else {
215+
Err(CallError)
216+
}
217+
}
218+
}
163219
}

core/src/env/srml/srml_only/sys.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ extern "C" {
3232
) -> u32;
3333

3434
/// Calls a remote smart contract.
35-
#[allow(unused)]
3635
pub fn ext_call(
3736
callee_ptr: u32,
3837
callee_len: u32,

core/src/env/srml/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ use scale::{
3030
#[cfg(feature = "ink-generate-abi")]
3131
use type_metadata::Metadata;
3232

33+
/// Errors encountered by calling a remote contract.
34+
///
35+
/// # Note
36+
///
37+
/// This is currently just a placeholder for potential future error codes.
38+
pub struct CallError;
39+
3340
/// The SRML fundamental types.
3441
#[allow(unused)]
3542
#[cfg_attr(feature = "test-env", derive(Debug, Clone, PartialEq, Eq))]

core/src/env/test_env.rs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
use super::*;
1818
use crate::{
19-
env::EnvTypes,
19+
env::{
20+
CallError,
21+
EnvTypes,
22+
},
2023
memory::collections::hash_map::{
2124
Entry,
2225
HashMap,
@@ -47,6 +50,25 @@ impl EventData {
4750
}
4851
}
4952

53+
/// Emulates the data given to remote smart contract call instructions.
54+
pub struct RawCallData {
55+
pub callee: Vec<u8>,
56+
pub gas: u64,
57+
pub value: Vec<u8>,
58+
pub input_data: Vec<u8>,
59+
}
60+
61+
/// Decoded call data of recorded external calls.
62+
pub struct CallData<E>
63+
where
64+
E: crate::env::EnvTypes,
65+
{
66+
pub callee: E::AccountId,
67+
pub gas: u64,
68+
pub value: E::Balance,
69+
pub input_data: Vec<u8>,
70+
}
71+
5072
/// An entry in the storage of the test environment.
5173
///
5274
/// # Note
@@ -173,6 +195,10 @@ pub struct TestEnvData {
173195
gas_left: Vec<u8>,
174196
/// The total transferred value.
175197
value_transferred: Vec<u8>,
198+
/// The recorded external calls.
199+
calls: Vec<CallData>,
200+
/// The expected return data of the next external call.
201+
call_return: Vec<u8>,
176202
/// Returned data.
177203
return_data: Vec<u8>,
178204
}
@@ -195,6 +221,8 @@ impl Default for TestEnvData {
195221
gas_left: Vec::new(),
196222
value_transferred: Vec::new(),
197223
dispatched_calls: Vec::new(),
224+
calls: Vec::new(),
225+
call_return: Vec::new(),
198226
return_data: Vec::new(),
199227
}
200228
}
@@ -215,6 +243,8 @@ impl TestEnvData {
215243
self.total_writes = 0;
216244
self.events.clear();
217245
self.dispatched_calls.clear();
246+
self.calls.clear();
247+
self.call_return.clear();
218248
self.return_data.clear();
219249
}
220250

@@ -309,6 +339,17 @@ impl TestEnvData {
309339
self.dispatched_calls.iter().map(Vec::as_slice)
310340
}
311341

342+
/// Records a new external call.
343+
pub fn add_call(&mut self, callee: &[u8], gas: u64, value: &[u8], input_data: &[u8]) {
344+
let new_call = CallData {
345+
callee: callee.to_vec(),
346+
gas,
347+
value: value.to_vec(),
348+
input_data: input_data.to_vec(),
349+
};
350+
self.calls.push(new_call);
351+
}
352+
312353
/// Returns the latest returned data.
313354
pub fn returned_data(&self) -> &[u8] {
314355
&self.return_data
@@ -392,6 +433,17 @@ impl TestEnvData {
392433
pub fn dispatch_call(&mut self, call: &[u8]) {
393434
self.add_dispatched_call(call);
394435
}
436+
437+
pub fn call(
438+
&mut self,
439+
callee: &[u8],
440+
gas: u64,
441+
value: &[u8],
442+
input_data: &[u8],
443+
) -> Vec<u8> {
444+
self.add_call(callee, gas, value, input_data);
445+
self.call_return.clone()
446+
}
395447
}
396448

397449
thread_local! {
@@ -541,6 +593,35 @@ where
541593
fn dispatch_raw_call(data: &[u8]) {
542594
TEST_ENV_DATA.with(|test_env| test_env.borrow_mut().dispatch_call(data))
543595
}
596+
597+
fn call_invoke(
598+
callee: T::AccountId,
599+
gas: u64,
600+
value: T::Balance,
601+
input_data: &[u8],
602+
) -> Result<(), CallError> {
603+
let callee = &(callee.encode())[..];
604+
let value = &(value.encode())[..];
605+
let _return_data = TEST_ENV_DATA
606+
.with(|test_env| test_env.borrow_mut().call(callee, gas, value, input_data));
607+
Ok(())
608+
}
609+
610+
fn call_evaluate<U: Decode>(
611+
callee: T::AccountId,
612+
gas: u64,
613+
value: T::Balance,
614+
input_data: &[u8],
615+
) -> Result<U, CallError> {
616+
let callee = &(callee.encode())[..];
617+
let value = &(value.encode())[..];
618+
TEST_ENV_DATA.with(|test_env| {
619+
U::decode(
620+
&mut &(test_env.borrow_mut().call(callee, gas, value, input_data))[..],
621+
)
622+
.map_err(|_| CallError)
623+
})
624+
}
544625
}
545626

546627
pub enum TestEnvStorage {}

core/src/env/traits.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
// along with ink!. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use crate::{
18+
env::CallError,
1819
memory::vec::Vec,
1920
storage::Key,
2021
};
21-
use scale::Codec;
22+
use scale::{
23+
Codec,
24+
Decode,
25+
};
2226

2327
#[cfg(not(feature = "test-env"))]
2428
/// The environmental types usable by contracts defined with ink!.
@@ -136,4 +140,20 @@ pub trait Env: EnvTypes {
136140

137141
/// Dispatches a call into the Runtime.
138142
fn dispatch_raw_call(data: &[u8]);
143+
144+
/// Calls a remote smart contract without returning data
145+
fn call_invoke(
146+
callee: <Self as EnvTypes>::AccountId,
147+
gas: u64,
148+
value: <Self as EnvTypes>::Balance,
149+
input_data: &[u8],
150+
) -> Result<(), CallError>;
151+
152+
/// Calls a remote smart contract and return encoded data
153+
fn call_evaluate<T: Decode>(
154+
callee: <Self as EnvTypes>::AccountId,
155+
gas: u64,
156+
value: <Self as EnvTypes>::Balance,
157+
input_data: &[u8],
158+
) -> Result<T, CallError>;
139159
}

model/src/exec_env.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use core::marker::PhantomData;
1919
use ink_core::{
2020
env::{
2121
self,
22+
CallError,
2223
Env,
2324
},
2425
storage::alloc::{
@@ -28,7 +29,10 @@ use ink_core::{
2829
Initialize,
2930
},
3031
};
31-
use scale::Encode as _;
32+
use scale::{
33+
Decode,
34+
Encode as _,
35+
};
3236

3337
/// Provides a safe interface to an environment given a contract state.
3438
pub struct ExecutionEnv<State, Env> {
@@ -194,4 +198,26 @@ impl<T: Env> EnvHandler<T> {
194198
{
195199
T::dispatch_raw_call(call.into().encode().as_slice())
196200
}
201+
202+
/// Calls a remote smart contract without returning data.
203+
pub fn call_invoke(
204+
&mut self,
205+
callee: T::AccountId,
206+
gas: u64,
207+
value: T::Balance,
208+
input_data: &[u8],
209+
) -> Result<(), CallError> {
210+
T::call_invoke(callee, gas, value, input_data)
211+
}
212+
213+
/// Calls a remote smart contract with returning encoded data.
214+
pub fn call_evaluate<U: Decode>(
215+
&mut self,
216+
callee: T::AccountId,
217+
gas: u64,
218+
value: T::Balance,
219+
input_data: &[u8],
220+
) -> Result<U, CallError> {
221+
T::call_evaluate(callee, gas, value, input_data)
222+
}
197223
}

0 commit comments

Comments
 (0)