api.rs 15.9 KB
Newer Older
1
// Copyright 2018-2021 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
//! The public raw interface towards the host Wasm engine.
Hero Bird's avatar
Hero Bird committed
16

17
use crate::{
18
    backend::{
19
        EnvBackend,
Hero Bird's avatar
Hero Bird committed
20
        ReturnFlags,
21
        TypedEnvBackend,
22
23
    },
    call::{
24
        utils::ReturnType,
25
        CallParams,
26
        CreateParams,
27
28
29
30
    },
    engine::{
        EnvInstance,
        OnInstance,
31
    },
32
33
34
35
    hash::{
        CryptoHash,
        HashOutput,
    },
36
    topics::Topics,
37
    Environment,
38
    Result,
39
};
40
41
42
43
44
45
46
47
48
use ink_primitives::Key;

/// Returns the address of the caller of the executed contract.
///
/// # Errors
///
/// If the returned caller cannot be properly decoded.
pub fn caller<T>() -> Result<T::AccountId>
where
49
    T: Environment,
50
{
51
52
53
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::caller::<T>(instance)
    })
54
55
56
57
58
59
60
61
62
}

/// Returns the transferred balance for the contract execution.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn transferred_balance<T>() -> Result<T::Balance>
where
63
    T: Environment,
64
65
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
66
        TypedEnvBackend::transferred_balance::<T>(instance)
67
68
69
    })
}

70
/// Returns the price for the specified amount of gas.
71
72
73
74
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
Hero Bird's avatar
Hero Bird committed
75
pub fn weight_to_fee<T>(gas: u64) -> Result<T::Balance>
76
where
77
    T: Environment,
78
79
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
80
        TypedEnvBackend::weight_to_fee::<T>(instance, gas)
81
82
83
84
85
86
87
88
89
90
    })
}

/// Returns the amount of gas left for the contract execution.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn gas_left<T>() -> Result<T::Balance>
where
91
    T: Environment,
92
{
93
94
95
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::gas_left::<T>(instance)
    })
96
97
98
99
100
101
102
103
104
}

/// Returns the current block timestamp.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn block_timestamp<T>() -> Result<T::Timestamp>
where
105
    T: Environment,
106
107
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
108
        TypedEnvBackend::block_timestamp::<T>(instance)
109
110
    })
}
111

112
/// Returns the account ID of the executed contract.
113
///
114
115
116
117
118
119
120
121
122
/// # Note
///
/// This method was formerly known as `address`.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn account_id<T>() -> Result<T::AccountId>
where
123
    T: Environment,
124
125
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
126
        TypedEnvBackend::account_id::<T>(instance)
127
128
129
130
131
132
    })
}

/// Returns the balance of the executed contract.
///
/// # Errors
133
///
134
135
136
/// If the returned value cannot be properly decoded.
pub fn balance<T>() -> Result<T::Balance>
where
137
    T: Environment,
138
{
139
140
141
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::balance::<T>(instance)
    })
142
143
144
145
146
147
148
149
150
}

/// Returns the current rent allowance for the executed contract.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn rent_allowance<T>() -> Result<T::Balance>
where
151
    T: Environment,
152
153
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
154
        TypedEnvBackend::rent_allowance::<T>(instance)
155
    })
156
157
}

158
/// Returns the current block number.
159
///
160
/// # Errors
161
///
162
163
164
/// If the returned value cannot be properly decoded.
pub fn block_number<T>() -> Result<T::BlockNumber>
where
165
    T: Environment,
166
167
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
168
        TypedEnvBackend::block_number::<T>(instance)
169
170
171
    })
}

172
/// Returns the minimum balance that is required for creating an account.
173
174
175
176
177
178
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn minimum_balance<T>() -> Result<T::Balance>
where
179
    T: Environment,
180
181
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
182
        TypedEnvBackend::minimum_balance::<T>(instance)
183
184
185
186
187
188
189
190
191
192
    })
}

/// Returns the tombstone deposit for the contracts chain.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn tombstone_deposit<T>() -> Result<T::Balance>
where
193
    T: Environment,
194
195
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
196
        TypedEnvBackend::tombstone_deposit::<T>(instance)
197
198
199
200
201
202
    })
}

/// Emits an event with the given event data.
pub fn emit_event<T, Event>(event: Event)
where
203
    T: Environment,
204
    Event: Topics + scale::Encode,
205
206
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
207
        TypedEnvBackend::emit_event::<T, Event>(instance, event)
208
    })
209
210
}

211
212
213
/// Sets the rent allowance of the executed contract to the new value.
pub fn set_rent_allowance<T>(new_value: T::Balance)
where
214
    T: Environment,
215
216
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
217
        TypedEnvBackend::set_rent_allowance::<T>(instance, new_value)
218
219
220
221
    })
}

/// Writes the value to the contract storage under the given key.
Hero Bird's avatar
Hero Bird committed
222
223
224
225
///
/// # Panics
///
/// - If the encode length of value exceeds the configured maximum value length of a storage entry.
226
pub fn set_contract_storage<V>(key: &Key, value: &V)
227
228
229
230
where
    V: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
231
        EnvBackend::set_contract_storage::<V>(instance, key, value)
232
233
234
235
    })
}

/// Returns the value stored under the given key in the contract's storage if any.
236
///
237
/// # Errors
238
///
Hero Bird's avatar
Hero Bird committed
239
240
/// - If the decoding of the typed value failed (`KeyNotFound`)
pub fn get_contract_storage<R>(key: &Key) -> Result<Option<R>>
241
242
243
244
where
    R: scale::Decode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
245
        EnvBackend::get_contract_storage::<R>(instance, key)
246
247
248
249
    })
}

/// Clears the contract's storage key entry.
250
pub fn clear_contract_storage(key: &Key) {
251
    <EnvInstance as OnInstance>::on_instance(|instance| {
252
        EnvBackend::clear_contract_storage(instance, key)
253
    })
Andrew Jones's avatar
Andrew Jones committed
254
255
}

256
/// Invokes a contract message.
257
///
258
259
260
261
262
263
264
265
266
/// # Note
///
/// - Prefer using this over [`eval_contract`] if possible. [`invoke_contract`]
///   will generally have a better performance since it won't try to fetch any results.
/// - This is a low level way to invoke another smart contract.
///   Prefer to use the ink! guided and type safe approach to using this.
///
/// # Errors
///
Hero Bird's avatar
Hero Bird committed
267
268
/// - If the called account does not exist.
/// - If the called account is not a contract.
269
270
271
272
/// - If the called contract is a tombstone.
/// - If arguments passed to the called contract message are invalid.
/// - If the called contract execution has trapped.
/// - If the called contract ran out of gas upon execution.
273
pub fn invoke_contract<T, Args>(params: &CallParams<T, Args, ()>) -> Result<()>
274
where
275
    T: Environment,
276
    Args: scale::Encode,
277
{
278
    <EnvInstance as OnInstance>::on_instance(|instance| {
279
        TypedEnvBackend::invoke_contract::<T, Args>(instance, params)
280
    })
281
}
282

283
284
285
286
287
288
/// Evaluates a contract message and returns its result.
///
/// # Note
///
/// This is a low level way to evaluate another smart contract.
/// Prefer to use the ink! guided and type safe approach to using this.
289
///
290
291
/// # Errors
///
Hero Bird's avatar
Hero Bird committed
292
293
/// - If the called account does not exist.
/// - If the called account is not a contract.
294
295
296
297
298
/// - If the called contract is a tombstone.
/// - If arguments passed to the called contract message are invalid.
/// - If the called contract execution has trapped.
/// - If the called contract ran out of gas upon execution.
/// - If the returned value failed to decode properly.
299
pub fn eval_contract<T, Args, R>(params: &CallParams<T, Args, ReturnType<R>>) -> Result<R>
300
where
301
    T: Environment,
302
    Args: scale::Encode,
303
    R: scale::Decode,
304
{
305
    <EnvInstance as OnInstance>::on_instance(|instance| {
306
        TypedEnvBackend::eval_contract::<T, Args, R>(instance, params)
307
    })
308
309
}

310
311
312
313
314
315
/// Instantiates another contract.
///
/// # Note
///
/// This is a low level way to instantiate another smart contract.
/// Prefer to use the ink! guided and type safe approach to using this.
316
///
317
318
319
320
321
322
323
324
/// # Errors
///
/// - If the code hash is invalid.
/// - If the arguments passed to the instantiation process are invalid.
/// - If the instantiation process traps.
/// - If the instantiation process runs out of gas.
/// - If given insufficient endowment.
/// - If the returned account ID failed to decode properly.
325
326
pub fn instantiate_contract<T, Args, Salt, C>(
    params: &CreateParams<T, Args, Salt, C>,
327
) -> Result<T::AccountId>
328
where
329
    T: Environment,
330
    Args: scale::Encode,
331
    Salt: AsRef<[u8]>,
332
{
333
    <EnvInstance as OnInstance>::on_instance(|instance| {
334
        TypedEnvBackend::instantiate_contract::<T, Args, Salt, C>(instance, params)
335
    })
336
}
337

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
/// Restores a smart contract in tombstone state.
///
/// # Params
///
/// - `account_id`: Account ID of the to-be-restored contract.
/// - `code_hash`: Code hash of the to-be-restored contract.
/// - `rent_allowance`: Rent allowance of the restored contract
///                     upon successful restoration.
/// - `filtered_keys`: Storage keys to be excluded when calculating the tombstone hash,
///                    which is used to decide whether the original contract and the
///                    to-be-restored contract have matching storage.
///
/// # Usage
///
/// A smart contract that has too few funds to pay for its storage fees
/// can eventually be evicted. An evicted smart contract `C` leaves behind
/// a tombstone associated with a hash that has been computed partially
/// by its storage contents.
///
/// To restore contract `C` back to a fully working contract the normal
/// process is to write another contract `C2` with the only purpose to
/// eventually have the absolutely same contract storage as `C` did when
/// it was evicted.
/// For that purpose `C2` can use other storage keys that have not been in
/// use by contract `C`.
/// Once `C2` contract storage matches the storage of `C` when it was evicted
/// `C2` can invoke this method in order to initiate restoration of `C`.
/// A tombstone hash is calculated for `C2` and if it matches the tombstone
/// hash of `C` the restoration is going to be successful.
/// The `filtered_keys` argument can be used to ignore the extraneous keys
/// used by `C2` but not used by `C`.
369
///
370
371
372
373
/// The process of such a smart contract restoration can generally be very expensive.
///
/// # Note
///
374
/// - `filtered_keys` can be used to ignore certain storage regions
375
376
377
378
379
380
381
///   in the restorer contract to not influence the hash calculations.
/// - Does *not* perform restoration right away but defers it to the end of
///   the contract execution.
/// - Restoration is cancelled if there is no tombstone in the destination
///   address or if the hashes don't match. No changes are made in this case.
pub fn restore_contract<T>(
    account_id: T::AccountId,
382
    code_hash: T::Hash,
383
384
385
    rent_allowance: T::Balance,
    filtered_keys: &[Key],
) where
386
    T: Environment,
387
388
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
389
        TypedEnvBackend::restore_contract::<T>(
390
391
392
393
394
395
396
397
398
            instance,
            account_id,
            code_hash,
            rent_allowance,
            filtered_keys,
        )
    })
}

399
400
401
402
403
404
405
406
407
/// Terminates the existence of the currently executed smart contract.
///
/// This removes the calling account and transfers all remaining balance
/// to the given beneficiary.
///
/// # Note
///
/// This function never returns. Either the termination was successful and the
/// execution of the destroyed contract is halted. Or it failed during the termination
408
/// which is considered fatal and results in a trap and rollback.
409
410
pub fn terminate_contract<T>(beneficiary: T::AccountId) -> !
where
411
    T: Environment,
412
413
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
414
        TypedEnvBackend::terminate_contract::<T>(instance, beneficiary)
415
416
417
    })
}

418
419
420
421
422
423
424
425
/// Transfers value from the contract to the destination account ID.
///
/// # Note
///
/// This is more efficient and simpler than the alternative to make a no-op
/// contract call or invoke a runtime function that performs the
/// transaction.
///
426
/// # Errors
427
///
428
/// - If the contract doesn't have sufficient funds.
429
/// - If the transfer had brought the sender's total balance below the
430
///   subsistence threshold.
431
432
pub fn transfer<T>(destination: T::AccountId, value: T::Balance) -> Result<()>
where
433
    T: Environment,
434
435
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
436
        TypedEnvBackend::transfer::<T>(instance, destination, value)
437
438
439
    })
}

440
/// Returns the execution input to the executed contract and decodes it as `T`.
441
442
443
444
445
///
/// # Note
///
/// - The input is the 4-bytes selector followed by the arguments
///   of the called function in their SCALE encoded representation.
446
447
448
449
450
451
/// - No prior interaction with the environment must take place before
///   calling this procedure.
///
/// # Usage
///
/// Normally contracts define their own `enum` dispatch types respective
452
453
/// to their exported constructors and messages that implement `scale::Decode`
/// according to the constructors or messages selectors and their arguments.
454
455
456
457
458
/// These `enum` dispatch types are then given to this procedure as the `T`.
///
/// When using ink! users do not have to construct those enum dispatch types
/// themselves as they are normally generated by the ink! code generation
/// automatically.
459
460
461
///
/// # Errors
///
462
463
464
465
466
/// If the given `T` cannot be properly decoded from the expected input.
pub fn decode_input<T>() -> Result<T>
where
    T: scale::Decode,
{
467
468
469
    <EnvInstance as OnInstance>::on_instance(|instance| {
        EnvBackend::decode_input::<T>(instance)
    })
470
471
472
473
474
475
}

/// Returns the value back to the caller of the executed contract.
///
/// # Note
///
Hero Bird's avatar
Hero Bird committed
476
477
/// This function  stops the execution of the contract immediately.
pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R) -> !
478
479
480
481
where
    R: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
482
        EnvBackend::return_value::<R>(instance, return_flags, return_value)
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
    })
}

/// Returns a random hash seed.
///
/// # Note
///
/// - The subject buffer can be used to further randomize the hash.
/// - Within the same execution returns the same random hash for the same subject.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn random<T>(subject: &[u8]) -> Result<T::Hash>
where
498
    T: Environment,
499
500
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
501
        TypedEnvBackend::random::<T>(instance, subject)
502
503
504
505
    })
}

/// Prints the given contents to the environmental log.
Hero Bird's avatar
Hero Bird committed
506
pub fn debug_println(content: &str) {
507
508
509
    <EnvInstance as OnInstance>::on_instance(|instance| {
        EnvBackend::println(instance, content)
    })
510
511
}

512
513
514
515
516
517
518
519
520
/// Conducts the crypto hash of the given input and stores the result in `output`.
pub fn hash_bytes<H>(input: &[u8], output: &mut <H as HashOutput>::Type)
where
    H: CryptoHash,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        instance.hash_bytes::<H>(input, output)
    })
}
521

522
523
524
525
526
/// Conducts the crypto hash of the given encoded input and stores the result in `output`.
///
/// # Example
///
/// ```
527
/// # use ink_env::hash::{Sha2x256, HashOutput};
528
529
530
531
532
533
/// const EXPECTED: [u8; 32] = [
///   243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248,  29, 136, 145, 115,
///   186, 134, 14, 175, 178, 99, 183,  21,   4, 94,  92,  69, 199, 207, 241, 179,
/// ];
/// let encodable = (42, "foo", true); // Implements `scale::Encode`
/// let mut output = <Sha2x256 as HashOutput>::Type::default(); // 256-bit buffer
534
/// ink_env::hash_encoded::<Sha2x256, _>(&encodable, &mut output);
535
536
537
538
539
540
541
542
543
544
/// assert_eq!(output, EXPECTED);
/// ```
pub fn hash_encoded<H, T>(input: &T, output: &mut <H as HashOutput>::Type)
where
    H: CryptoHash,
    T: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        instance.hash_encoded::<H, T>(input, output)
    })
545
}