impls.rs 15.3 KB
Newer Older
1
// Copyright 2018-2021 Parity Technologies (UK) Ltd.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// 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
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// 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.

use super::{
    ext,
    EnvInstance,
Hero Bird's avatar
Hero Bird committed
18
19
    Error as ExtError,
    ScopedBuffer,
20
};
21
use crate::{
22
    call::{
23
        utils::ReturnType,
24
        CallParams,
25
        CreateParams,
26
    },
Hero Bird's avatar
Hero Bird committed
27
28
29
30
31
32
33
34
    hash::{
        Blake2x128,
        Blake2x256,
        CryptoHash,
        HashOutput,
        Keccak256,
        Sha2x256,
    },
35
36
37
38
    topics::{
        Topics,
        TopicsBuilderBackend,
    },
39
40
41
42
    types::{
        RentParams,
        RentStatus,
    },
43
    Clear,
44
45
46
    EnvBackend,
    Environment,
    Error,
47
    Result,
Hero Bird's avatar
Hero Bird committed
48
    ReturnFlags,
49
    TypedEnvBackend,
50
51
52
};
use ink_primitives::Key;

53
54
55
impl CryptoHash for Blake2x128 {
    fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
        type OutputType = [u8; 16];
56
57
58
59
        static_assertions::assert_type_eq_all!(
            <Blake2x128 as HashOutput>::Type,
            OutputType
        );
60
61
62
63
64
65
66
67
        let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 16);
        ext::hash_blake2_128(input, output);
    }
}

impl CryptoHash for Blake2x256 {
    fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
        type OutputType = [u8; 32];
68
69
70
71
        static_assertions::assert_type_eq_all!(
            <Blake2x256 as HashOutput>::Type,
            OutputType
        );
72
73
74
75
76
77
78
79
        let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
        ext::hash_blake2_256(input, output);
    }
}

impl CryptoHash for Sha2x256 {
    fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
        type OutputType = [u8; 32];
80
81
82
83
        static_assertions::assert_type_eq_all!(
            <Sha2x256 as HashOutput>::Type,
            OutputType
        );
84
85
86
87
88
89
90
91
        let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
        ext::hash_sha2_256(input, output);
    }
}

impl CryptoHash for Keccak256 {
    fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
        type OutputType = [u8; 32];
92
93
94
95
        static_assertions::assert_type_eq_all!(
            <Keccak256 as HashOutput>::Type,
            OutputType
        );
96
97
98
99
100
        let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
        ext::hash_keccak_256(input, output);
    }
}

101
impl From<ext::Error> for Error {
Hero Bird's avatar
Hero Bird committed
102
103
104
105
106
107
108
109
110
111
112
    fn from(ext_error: ext::Error) -> Self {
        match ext_error {
            ext::Error::UnknownError => Self::UnknownError,
            ext::Error::CalleeTrapped => Self::CalleeTrapped,
            ext::Error::CalleeReverted => Self::CalleeReverted,
            ext::Error::KeyNotFound => Self::KeyNotFound,
            ext::Error::BelowSubsistenceThreshold => Self::BelowSubsistenceThreshold,
            ext::Error::TransferFailed => Self::TransferFailed,
            ext::Error::NewContractNotFunded => Self::NewContractNotFunded,
            ext::Error::CodeNotFound => Self::CodeNotFound,
            ext::Error::NotCallable => Self::NotCallable,
113
            ext::Error::LoggingDisabled => Self::LoggingDisabled,
Hero Bird's avatar
Hero Bird committed
114
        }
115
    }
Hero Bird's avatar
Hero Bird committed
116
}
117

118
119
120
121
122
123
124
pub struct TopicsBuilder<'a, E> {
    scoped_buffer: ScopedBuffer<'a>,
    marker: core::marker::PhantomData<fn() -> E>,
}

impl<'a, E> From<ScopedBuffer<'a>> for TopicsBuilder<'a, E>
where
125
    E: Environment,
126
127
128
129
130
131
132
133
134
135
136
{
    fn from(scoped_buffer: ScopedBuffer<'a>) -> Self {
        Self {
            scoped_buffer,
            marker: Default::default(),
        }
    }
}

impl<'a, E> TopicsBuilderBackend<E> for TopicsBuilder<'a, E>
where
137
    E: Environment,
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{
    type Output = (ScopedBuffer<'a>, &'a mut [u8]);

    fn expect(&mut self, expected_topics: usize) {
        self.scoped_buffer
            .append_encoded(&scale::Compact(expected_topics as u32));
    }

    fn push_topic<T>(&mut self, topic_value: &T)
    where
        T: scale::Encode,
    {
        let mut split = self.scoped_buffer.split();
        let encoded = split.take_encoded(topic_value);
        let len_encoded = encoded.len();
153
        let mut result = <E as Environment>::Hash::clear();
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
        let len_result = result.as_ref().len();
        if len_encoded <= len_result {
            result.as_mut()[..len_encoded].copy_from_slice(encoded);
        } else {
            let mut hash_output = <Blake2x256 as HashOutput>::Type::default();
            <Blake2x256 as CryptoHash>::hash(encoded, &mut hash_output);
            let copy_len = core::cmp::min(hash_output.len(), len_result);
            result.as_mut()[0..copy_len].copy_from_slice(&hash_output[0..copy_len]);
        }
        self.scoped_buffer.append_encoded(&result);
    }

    fn output(mut self) -> Self::Output {
        let encoded_topics = self.scoped_buffer.take_appended();
        (self.scoped_buffer, encoded_topics)
    }
}

Hero Bird's avatar
Hero Bird committed
172
impl EnvInstance {
173
    /// Returns a new scoped buffer for the entire scope of the static 16 kB buffer.
Hero Bird's avatar
Hero Bird committed
174
175
    fn scoped_buffer(&mut self) -> ScopedBuffer {
        ScopedBuffer::from(&mut self.buffer[..])
176
177
178
    }

    /// Returns the contract property value.
Hero Bird's avatar
Hero Bird committed
179
    fn get_property<T>(&mut self, ext_fn: fn(output: &mut &mut [u8])) -> Result<T>
180
181
182
    where
        T: scale::Decode,
    {
Hero Bird's avatar
Hero Bird committed
183
184
185
        let full_scope = &mut self.scoped_buffer().take_rest();
        ext_fn(full_scope);
        scale::Decode::decode(&mut &full_scope[..]).map_err(Into::into)
186
187
188
    }

    /// Reusable implementation for invoking another contract message.
Hero Bird's avatar
Hero Bird committed
189
    fn invoke_contract_impl<T, Args, RetType, R>(
190
        &mut self,
Hero Bird's avatar
Hero Bird committed
191
192
        params: &CallParams<T, Args, RetType>,
    ) -> Result<R>
193
    where
194
        T: Environment,
195
        Args: scale::Encode,
Hero Bird's avatar
Hero Bird committed
196
        R: scale::Decode,
197
    {
Hero Bird's avatar
Hero Bird committed
198
199
200
201
        let mut scope = self.scoped_buffer();
        let gas_limit = params.gas_limit();
        let enc_callee = scope.take_encoded(params.callee());
        let enc_transferred_value = scope.take_encoded(params.transferred_value());
202
        let enc_input = scope.take_encoded(params.exec_input());
Hero Bird's avatar
Hero Bird committed
203
        let output = &mut scope.take_rest();
204
        ext::call(
Hero Bird's avatar
Hero Bird committed
205
206
207
208
209
210
211
212
            enc_callee,
            gas_limit,
            enc_transferred_value,
            enc_input,
            output,
        )?;
        let decoded = scale::Decode::decode(&mut &output[..])?;
        Ok(decoded)
213
214
215
    }
}

216
impl EnvBackend for EnvInstance {
217
    fn set_contract_storage<V>(&mut self, key: &Key, value: &V)
218
219
220
    where
        V: scale::Encode,
    {
Hero Bird's avatar
Hero Bird committed
221
222
        let buffer = self.scoped_buffer().take_encoded(value);
        ext::set_storage(key.as_bytes(), &buffer[..]);
223
224
    }

Hero Bird's avatar
Hero Bird committed
225
    fn get_contract_storage<R>(&mut self, key: &Key) -> Result<Option<R>>
226
227
228
    where
        R: scale::Decode,
    {
Hero Bird's avatar
Hero Bird committed
229
230
231
232
233
        let output = &mut self.scoped_buffer().take_rest();
        match ext::get_storage(key.as_bytes(), output) {
            Ok(_) => (),
            Err(ExtError::KeyNotFound) => return Ok(None),
            Err(_) => panic!("encountered unexpected error"),
234
        }
Hero Bird's avatar
Hero Bird committed
235
236
        let decoded = scale::Decode::decode(&mut &output[..])?;
        Ok(Some(decoded))
237
238
    }

239
    fn clear_contract_storage(&mut self, key: &Key) {
240
241
242
        ext::clear_storage(key.as_bytes())
    }

243
244
245
246
    fn decode_input<T>(&mut self) -> Result<T>
    where
        T: scale::Decode,
    {
Hero Bird's avatar
Hero Bird committed
247
        self.get_property::<T>(ext::input)
248
249
    }

Hero Bird's avatar
Hero Bird committed
250
    fn return_value<R>(&mut self, flags: ReturnFlags, return_value: &R) -> !
251
252
253
    where
        R: scale::Encode,
    {
Hero Bird's avatar
Hero Bird committed
254
255
256
        let mut scope = self.scoped_buffer();
        let enc_return_value = scope.take_encoded(return_value);
        ext::return_value(flags, enc_return_value);
257
258
    }

259
260
    fn debug_message(&mut self, content: &str) {
        ext::debug_message(content)
261
    }
262

263
264
265
266
267
    fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
    where
        H: CryptoHash,
    {
        <H as CryptoHash>::hash(input, output)
268
269
    }

270
271
272
273
274
275
276
277
    fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
    where
        H: CryptoHash,
        T: scale::Encode,
    {
        let mut scope = self.scoped_buffer();
        let enc_input = scope.take_encoded(input);
        <H as CryptoHash>::hash(enc_input, output)
278
    }
Hero Bird's avatar
Hero Bird committed
279

280
281
282
283
284
285
286
    fn call_chain_extension<I, T, E, ErrorCode, F, D>(
        &mut self,
        func_id: u32,
        input: &I,
        status_to_result: F,
        decode_to_result: D,
    ) -> ::core::result::Result<T, E>
Hero Bird's avatar
Hero Bird committed
287
288
    where
        I: scale::Encode,
289
290
291
292
        T: scale::Decode,
        E: From<ErrorCode>,
        F: FnOnce(u32) -> ::core::result::Result<(), ErrorCode>,
        D: FnOnce(&[u8]) -> ::core::result::Result<T, E>,
Hero Bird's avatar
Hero Bird committed
293
294
295
296
    {
        let mut scope = self.scoped_buffer();
        let enc_input = scope.take_encoded(input);
        let output = &mut scope.take_rest();
297
298
299
        status_to_result(ext::call_chain_extension(func_id, enc_input, output))?;
        let decoded = decode_to_result(&mut &output[..])?;
        Ok(decoded)
Hero Bird's avatar
Hero Bird committed
300
    }
301
302
}

303
304
impl TypedEnvBackend for EnvInstance {
    fn caller<T: Environment>(&mut self) -> Result<T::AccountId> {
305
306
307
        self.get_property::<T::AccountId>(ext::caller)
    }

308
    fn transferred_balance<T: Environment>(&mut self) -> Result<T::Balance> {
309
310
311
        self.get_property::<T::Balance>(ext::value_transferred)
    }

312
    fn gas_left<T: Environment>(&mut self) -> Result<T::Balance> {
313
314
315
        self.get_property::<T::Balance>(ext::gas_left)
    }

316
    fn block_timestamp<T: Environment>(&mut self) -> Result<T::Timestamp> {
317
318
319
        self.get_property::<T::Timestamp>(ext::now)
    }

320
    fn account_id<T: Environment>(&mut self) -> Result<T::AccountId> {
321
322
323
        self.get_property::<T::AccountId>(ext::address)
    }

324
    fn balance<T: Environment>(&mut self) -> Result<T::Balance> {
325
326
327
        self.get_property::<T::Balance>(ext::balance)
    }

328
    fn rent_allowance<T: Environment>(&mut self) -> Result<T::Balance> {
329
330
331
        self.get_property::<T::Balance>(ext::rent_allowance)
    }

332
    fn block_number<T: Environment>(&mut self) -> Result<T::BlockNumber> {
333
334
335
        self.get_property::<T::BlockNumber>(ext::block_number)
    }

336
    fn minimum_balance<T: Environment>(&mut self) -> Result<T::Balance> {
337
338
339
        self.get_property::<T::Balance>(ext::minimum_balance)
    }

340
    fn tombstone_deposit<T: Environment>(&mut self) -> Result<T::Balance> {
341
342
343
344
345
        self.get_property::<T::Balance>(ext::tombstone_deposit)
    }

    fn emit_event<T, Event>(&mut self, event: Event)
    where
346
        T: Environment,
347
        Event: Topics + scale::Encode,
348
    {
349
350
        let (mut scope, enc_topics) =
            event.topics::<T, _>(TopicsBuilder::from(self.scoped_buffer()).into());
Hero Bird's avatar
Hero Bird committed
351
352
        let enc_data = scope.take_encoded(&event);
        ext::deposit_event(enc_topics, enc_data);
353
354
355
356
    }

    fn set_rent_allowance<T>(&mut self, new_value: T::Balance)
    where
357
        T: Environment,
358
    {
Hero Bird's avatar
Hero Bird committed
359
360
        let buffer = self.scoped_buffer().take_encoded(&new_value);
        ext::set_rent_allowance(&buffer[..])
361
362
    }

363
364
365
366
367
368
369
    fn rent_params<T>(&mut self) -> Result<RentParams<T>>
    where
        T: Environment,
    {
        self.get_property::<RentParams<T>>(ext::rent_params)
    }

370
371
372
373
374
375
376
377
378
379
380
381
    fn rent_status<T>(
        &mut self,
        at_refcount: Option<core::num::NonZeroU32>,
    ) -> Result<RentStatus<T>>
    where
        T: Environment,
    {
        let output = &mut self.scoped_buffer().take_rest();
        ext::rent_status(at_refcount, output);
        scale::Decode::decode(&mut &output[..]).map_err(Into::into)
    }

382
383
384
385
    fn invoke_contract<T, Args>(
        &mut self,
        call_params: &CallParams<T, Args, ()>,
    ) -> Result<()>
386
    where
387
        T: Environment,
388
        Args: scale::Encode,
389
390
391
392
    {
        self.invoke_contract_impl(call_params)
    }

393
    fn eval_contract<T, Args, R>(
394
        &mut self,
395
        call_params: &CallParams<T, Args, ReturnType<R>>,
396
397
    ) -> Result<R>
    where
398
        T: Environment,
399
        Args: scale::Encode,
400
401
        R: scale::Decode,
    {
Hero Bird's avatar
Hero Bird committed
402
        self.invoke_contract_impl(call_params)
403
404
    }

405
    fn instantiate_contract<T, Args, Salt, C>(
406
        &mut self,
407
        params: &CreateParams<T, Args, Salt, C>,
408
409
    ) -> Result<T::AccountId>
    where
410
        T: Environment,
411
        Args: scale::Encode,
412
        Salt: AsRef<[u8]>,
413
    {
Hero Bird's avatar
Hero Bird committed
414
415
416
417
        let mut scoped = self.scoped_buffer();
        let gas_limit = params.gas_limit();
        let enc_code_hash = scoped.take_encoded(params.code_hash());
        let enc_endowment = scoped.take_encoded(params.endowment());
418
        let enc_input = scoped.take_encoded(params.exec_input());
Hero Bird's avatar
Hero Bird committed
419
420
421
422
        // We support `AccountId` types with an encoding that requires up to
        // 1024 bytes. Beyond that limit ink! contracts will trap for now.
        // In the default configuration encoded `AccountId` require 32 bytes.
        let out_address = &mut scoped.take(1024);
423
        let salt = params.salt_bytes().as_ref();
Hero Bird's avatar
Hero Bird committed
424
425
426
427
428
429
430
431
432
433
434
435
        let out_return_value = &mut scoped.take_rest();
        // We currently do nothing with the `out_return_value` buffer.
        // This should change in the future but for that we need to add support
        // for constructors that may return values.
        // This is useful to support fallible constructors for example.
        ext::instantiate(
            enc_code_hash,
            gas_limit,
            enc_endowment,
            enc_input,
            out_address,
            out_return_value,
436
            salt,
Hero Bird's avatar
Hero Bird committed
437
438
439
        )?;
        let account_id = scale::Decode::decode(&mut &out_address[..])?;
        Ok(account_id)
440
441
442
443
444
445
446
447
448
    }

    fn restore_contract<T>(
        &mut self,
        account_id: T::AccountId,
        code_hash: T::Hash,
        rent_allowance: T::Balance,
        filtered_keys: &[Key],
    ) where
449
        T: Environment,
450
    {
Hero Bird's avatar
Hero Bird committed
451
452
453
454
455
456
457
458
459
460
        let mut scope = self.scoped_buffer();
        let enc_account_id = scope.take_encoded(&account_id);
        let enc_code_hash = scope.take_encoded(&code_hash);
        let enc_rent_allowance = scope.take_encoded(&rent_allowance);
        ext::restore_to(
            enc_account_id,
            enc_code_hash,
            enc_rent_allowance,
            filtered_keys,
        );
461
462
    }

463
464
    fn terminate_contract<T>(&mut self, beneficiary: T::AccountId) -> !
    where
465
        T: Environment,
466
    {
Hero Bird's avatar
Hero Bird committed
467
468
        let buffer = self.scoped_buffer().take_encoded(&beneficiary);
        ext::terminate(&buffer[..]);
469
470
    }

471
472
    fn transfer<T>(&mut self, destination: T::AccountId, value: T::Balance) -> Result<()>
    where
473
        T: Environment,
474
    {
Hero Bird's avatar
Hero Bird committed
475
476
477
478
        let mut scope = self.scoped_buffer();
        let enc_destination = scope.take_encoded(&destination);
        let enc_value = scope.take_encoded(&value);
        ext::transfer(enc_destination, enc_value).map_err(Into::into)
479
480
    }

481
    fn weight_to_fee<T: Environment>(&mut self, gas: u64) -> Result<T::Balance> {
Hero Bird's avatar
Hero Bird committed
482
483
484
        let output = &mut self.scoped_buffer().take_rest();
        ext::weight_to_fee(gas, output);
        scale::Decode::decode(&mut &output[..]).map_err(Into::into)
485
486
    }

487
    fn random<T>(&mut self, subject: &[u8]) -> Result<(T::Hash, T::BlockNumber)>
488
    where
489
        T: Environment,
490
    {
Hero Bird's avatar
Hero Bird committed
491
492
493
494
495
        let mut scope = self.scoped_buffer();
        let enc_subject = scope.take_bytes(subject);
        let output = &mut scope.take_rest();
        ext::random(enc_subject, output);
        scale::Decode::decode(&mut &output[..]).map_err(Into::into)
496
497
    }
}