ext.rs 9.92 KB
Newer Older
1
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
2
//
3
4
5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
10
11
12
13
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
14
15
16
17
18

//! External C API to communicate with substrate contracts runtime module.
//!
//! Refer to substrate SRML contract module for more documentation.

19
20
21
use crate::env::{
    EnvError,
    Result,
22
};
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
use ink_primitives::Key;

/// Returned by the host environment if a contract call trapped.
const TRAP_RETURN_CODE: u32 = 0x0100;

mod sys {
    extern "C" {
        pub fn ext_instantiate(
            init_code_ptr: u32,
            init_code_len: u32,
            gas: u64,
            value_ptr: u32,
            value_len: u32,
            input_data_ptr: u32,
            input_data_len: u32,
        ) -> u32;

        pub fn ext_call(
            callee_ptr: u32,
            callee_len: u32,
            gas: u64,
            value_ptr: u32,
            value_len: u32,
            input_data_ptr: u32,
            input_data_len: u32,
        ) -> u32;

50
51
52
53
54
55
56
        pub fn ext_transfer(
            account_id_ptr: u32,
            account_id_len: u32,
            value_ptr: u32,
            value_len: u32,
        ) -> u32;

57
58
59
60
61
62
63
        pub fn ext_deposit_event(
            topics_ptr: u32,
            topics_len: u32,
            data_ptr: u32,
            data_len: u32,
        );

64
65
        pub fn ext_set_storage(key_ptr: u32, value_ptr: u32, value_len: u32);
        pub fn ext_clear_storage(key_ptr: u32);
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        pub fn ext_get_storage(key_ptr: u32) -> u32;

        pub fn ext_get_runtime_storage(key_ptr: u32, key_len: u32) -> u32;

        pub fn ext_restore_to(
            dest_ptr: u32,
            dest_len: u32,
            code_hash_ptr: u32,
            code_hash_len: u32,
            rent_allowance_ptr: u32,
            rent_allowance_len: u32,
            delta_ptr: u32,
            delta_count: u32,
        );
80
        pub fn ext_terminate(beneficiary_ptr: u32, beneficiary_len: u32) -> !;
81
82
83
84
85
86
87
88
89
90
91

        pub fn ext_dispatch_call(call_ptr: u32, call_len: u32);

        pub fn ext_scratch_size() -> u32;
        pub fn ext_scratch_read(dst_ptr: u32, offset: u32, len: u32);
        pub fn ext_scratch_write(src_ptr: u32, len: u32);

        pub fn ext_caller();
        pub fn ext_block_number();
        pub fn ext_address();
        pub fn ext_balance();
92
        pub fn ext_gas_price(gas: u64);
93
94
95
96
97
98
99
100
101
102
103
        pub fn ext_gas_left();
        pub fn ext_value_transferred();
        pub fn ext_now();
        pub fn ext_rent_allowance();
        pub fn ext_minimum_balance();
        pub fn ext_tombstone_deposit();

        pub fn ext_set_rent_allowance(value_ptr: u32, value_len: u32);

        pub fn ext_random_seed(subject_ptr: u32, subject_len: u32);
        pub fn ext_println(str_ptr: u32, str_len: u32);
104
105
106
107
108

        pub fn ext_hash_keccak_256(input_ptr: u32, input_len: u32, output_ptr: u32);
        pub fn ext_hash_blake2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
        pub fn ext_hash_blake2_128(input_ptr: u32, input_len: u32, output_ptr: u32);
        pub fn ext_hash_sha2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
109
110
    }
}
111
112
113
114
115
116

pub fn create(
    code_hash: &[u8],
    gas_limit: u64,
    value: &[u8],
    create_data: &[u8],
117
118
) -> Result<()> {
    let ret_code = unsafe {
119
        sys::ext_instantiate(
120
121
122
123
124
125
126
127
            code_hash.as_ptr() as u32,
            code_hash.len() as u32,
            gas_limit,
            value.as_ptr() as u32,
            value.len() as u32,
            create_data.as_ptr() as u32,
            create_data.len() as u32,
        )
128
129
130
131
132
133
    };
    match ret_code {
        0 => Ok(()),
        c if c == TRAP_RETURN_CODE => Err(EnvError::ContractInstantiationTrapped),
        err if err <= 0xFF => Err(EnvError::ContractInstantiationFailState(err as u8)),
        _unknown => panic!("encountered unknown error code upon contract call"),
134
135
136
    }
}

137
138
pub fn call(callee: &[u8], gas_limit: u64, value: &[u8], call_data: &[u8]) -> Result<()> {
    let ret_code = unsafe {
139
140
141
142
143
144
145
146
147
        sys::ext_call(
            callee.as_ptr() as u32,
            callee.len() as u32,
            gas_limit,
            value.as_ptr() as u32,
            value.len() as u32,
            call_data.as_ptr() as u32,
            call_data.len() as u32,
        )
148
149
150
151
152
153
    };
    match ret_code {
        0 => Ok(()),
        c if c == TRAP_RETURN_CODE => Err(EnvError::ContractInstantiationTrapped),
        err if err <= 0xFF => Err(EnvError::ContractInstantiationFailState(err as u8)),
        _unknown => panic!("encountered unknown error code upon contract call"),
154
155
156
    }
}

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
pub fn transfer(account_id: &[u8], value: &[u8]) -> Result<()> {
    let ret_code = unsafe {
        sys::ext_transfer(
            account_id.as_ptr() as u32,
            account_id.len() as u32,
            value.as_ptr() as u32,
            value.len() as u32,
        )
    };
    match ret_code {
        0 => Ok(()),
        1 => Err(EnvError::TransferCallFailed),
        _unknown => panic!("encountered unknown error code upon transfer"),
    }
}

173
174
175
176
177
178
179
180
181
182
183
pub fn deposit_event(topics: &[u8], data: &[u8]) {
    unsafe {
        sys::ext_deposit_event(
            topics.as_ptr() as u32,
            topics.len() as u32,
            data.as_ptr() as u32,
            data.len() as u32,
        )
    }
}

184
185
186
187
188
189
190
pub fn set_storage(key: &[u8], encoded_value: &[u8]) {
    unsafe {
        sys::ext_set_storage(
            key.as_ptr() as u32,
            encoded_value.as_ptr() as u32,
            encoded_value.len() as u32,
        )
191
192
193
    }
}

194
pub fn clear_storage(key: &[u8]) {
195
    unsafe { sys::ext_clear_storage(key.as_ptr() as u32) }
196
197
}

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
pub fn get_storage(key: &[u8]) -> Result<()> {
    let ret_code = unsafe { sys::ext_get_storage(key.as_ptr() as u32) };
    match ret_code {
        0 => Ok(()),
        1 => Err(EnvError::MissingContractStorageEntry),
        _unknown => panic!("encountered unexpected return code"),
    }
}

pub fn get_runtime_storage(runtime_key: &[u8]) -> Result<()> {
    let ret_code = unsafe {
        sys::ext_get_runtime_storage(
            runtime_key.as_ptr() as u32,
            runtime_key.len() as u32,
        )
    };
    match ret_code {
        0 => Ok(()),
        1 => Err(EnvError::MissingRuntimeStorageEntry),
        _unknown => panic!("encountered unsupported return code"),
    }
219
220
}

221
222
223
224
225
226
227
228
229
230
231
/// Restores a tombstone to the original smart contract.
///
/// # Params
///
/// - `account_id`: Encoded bytes of the `AccountId` of the to-be-restored contract.
/// - `code_hash`: Encoded code hash of the to-be-restored contract.
/// - `rent_allowance`: The encoded rent allowance of the restored contract
///                     upon successful restoration.
/// - `filtered_keys`: Storage keys that will be ignored for the tombstone hash
///                    match calculation that decide whether the original contract
///                    storage and the storage of the restorer contract is equal.
232
pub fn restore_to(
233
    account_id: &[u8],
234
235
236
237
238
239
    code_hash: &[u8],
    rent_allowance: &[u8],
    filtered_keys: &[Key],
) {
    unsafe {
        sys::ext_restore_to(
240
241
            account_id.as_ptr() as u32,
            account_id.len() as u32,
242
243
244
245
246
247
248
249
250
251
            code_hash.as_ptr() as u32,
            code_hash.len() as u32,
            rent_allowance.as_ptr() as u32,
            rent_allowance.len() as u32,
            filtered_keys.as_ptr() as u32,
            filtered_keys.len() as u32,
        )
    }
}

252
253
254
255
pub fn terminate(beneficiary: &[u8]) -> ! {
    unsafe { sys::ext_terminate(beneficiary.as_ptr() as u32, beneficiary.len() as u32) }
}

256
257
258
259
260
261
262
263
pub fn dispatch_call(call: &[u8]) {
    unsafe { sys::ext_dispatch_call(call.as_ptr() as u32, call.len() as u32) }
}

pub fn scratch_size() -> usize {
    (unsafe { sys::ext_scratch_size() }) as usize
}

264
265
pub fn scratch_read(dest: &mut [u8], offset: u32) {
    unsafe { sys::ext_scratch_read(dest.as_mut_ptr() as u32, offset, dest.len() as u32) }
266
267
}

268
269
pub fn scratch_write(src: &[u8]) {
    unsafe { sys::ext_scratch_write(src.as_ptr() as u32, src.len() as u32) }
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
}

macro_rules! impl_ext_wrapper_for {
    ( $( ($name:ident => $ext_name:ident), )* ) => {
        $(
            pub fn $name() {
                unsafe {
                    sys::$ext_name()
                }
            }
        )*
    }
}
impl_ext_wrapper_for! {
    (caller => ext_caller),
    (block_number => ext_block_number),
    (address => ext_address),
    (balance => ext_balance),
    (gas_left => ext_gas_left),
    (value_transferred => ext_value_transferred),
    (now => ext_now),
    (rent_allowance => ext_rent_allowance),
    (minimum_balance => ext_minimum_balance),
293
    (tombstone_deposit => ext_tombstone_deposit),
294
295
}

296
297
298
299
pub fn gas_price(gas: u64) {
    unsafe { sys::ext_gas_price(gas) }
}

300
301
pub fn set_rent_allowance(value: &[u8]) {
    unsafe { sys::ext_set_rent_allowance(value.as_ptr() as u32, value.len() as u32) }
302
303
304
305
306
307
308
309
310
311
}

pub fn random_seed(subject: &[u8]) {
    unsafe { sys::ext_random_seed(subject.as_ptr() as u32, subject.len() as u32) }
}

pub fn println(content: &str) {
    let bytes = content.as_bytes();
    unsafe { sys::ext_println(bytes.as_ptr() as u32, bytes.len() as u32) }
}
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

macro_rules! impl_hash_fn {
    ( $name:ident, $bytes_result:literal ) => {
        paste::item! {
            pub fn [<hash_ $name>](input: &[u8], output: &mut [u8; $bytes_result]) {
                unsafe {
                    sys::[<ext_hash_ $name>](
                        input.as_ptr() as u32,
                        input.len() as u32,
                        output.as_ptr() as u32,
                    )
                }
            }
        }
    };
}
impl_hash_fn!(sha2_256, 32);
impl_hash_fn!(keccak_256, 32);
impl_hash_fn!(blake2_256, 32);
impl_hash_fn!(blake2_128, 16);