api.rs 17.6 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
38
39
40
    types::{
        RentParams,
        RentStatus,
    },
41
    Environment,
42
    Result,
43
};
44
45
46
47
48
49
50
51
52
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
53
    T: Environment,
54
{
55
56
57
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::caller::<T>(instance)
    })
58
59
60
61
62
63
64
65
66
}

/// 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
67
    T: Environment,
68
69
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
70
        TypedEnvBackend::transferred_balance::<T>(instance)
71
72
73
    })
}

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

/// 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
95
    T: Environment,
96
{
97
98
99
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::gas_left::<T>(instance)
    })
100
101
102
103
104
105
106
107
108
}

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

116
/// Returns the account ID of the executed contract.
117
///
118
119
120
121
122
123
124
125
126
/// # 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
127
    T: Environment,
128
129
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
130
        TypedEnvBackend::account_id::<T>(instance)
131
132
133
134
135
136
    })
}

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

/// 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
155
    T: Environment,
156
157
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
158
        TypedEnvBackend::rent_allowance::<T>(instance)
159
    })
160
161
}

162
163
164
165
166
167
168
169
170
171
172
173
174
175
/// Returns information needed for rent calculations.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn rent_params<T>() -> Result<RentParams<T>>
where
    T: Environment,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::rent_params::<T>(instance)
    })
}

176
177
178
179
/// Returns information about the required deposit and resulting rent.
///
/// # Parameters
///
180
/// - `at_refcount`: The `refcount` assumed for the returned `custom_refcount_*` fields.
181
182
183
///   If `None` is supplied the `custom_refcount_*` fields will also be `None`.
///
///   The `current_*` fields of `RentStatus` do **not** consider changes to the code's
184
///   `refcount` made during the currently running call.
185
186
187
188
189
190
191
192
193
194
195
196
197
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn rent_status<T>(at_refcount: Option<core::num::NonZeroU32>) -> Result<RentStatus<T>>
where
    T: Environment,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnvBackend::rent_status::<T>(instance, at_refcount)
    })
}

198
/// Returns the current block number.
199
///
200
/// # Errors
201
///
202
203
204
/// If the returned value cannot be properly decoded.
pub fn block_number<T>() -> Result<T::BlockNumber>
where
205
    T: Environment,
206
207
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
208
        TypedEnvBackend::block_number::<T>(instance)
209
210
211
    })
}

212
/// Returns the minimum balance that is required for creating an account.
213
214
215
216
217
218
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn minimum_balance<T>() -> Result<T::Balance>
where
219
    T: Environment,
220
221
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
222
        TypedEnvBackend::minimum_balance::<T>(instance)
223
224
225
226
227
228
229
230
231
232
    })
}

/// 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
233
    T: Environment,
234
235
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
236
        TypedEnvBackend::tombstone_deposit::<T>(instance)
237
238
239
240
241
242
    })
}

/// Emits an event with the given event data.
pub fn emit_event<T, Event>(event: Event)
where
243
    T: Environment,
244
    Event: Topics + scale::Encode,
245
246
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
247
        TypedEnvBackend::emit_event::<T, Event>(instance, event)
248
    })
249
250
}

251
252
253
/// Sets the rent allowance of the executed contract to the new value.
pub fn set_rent_allowance<T>(new_value: T::Balance)
where
254
    T: Environment,
255
256
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
257
        TypedEnvBackend::set_rent_allowance::<T>(instance, new_value)
258
259
260
261
    })
}

/// Writes the value to the contract storage under the given key.
Hero Bird's avatar
Hero Bird committed
262
263
264
265
///
/// # Panics
///
/// - If the encode length of value exceeds the configured maximum value length of a storage entry.
266
pub fn set_contract_storage<V>(key: &Key, value: &V)
267
268
269
270
where
    V: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
271
        EnvBackend::set_contract_storage::<V>(instance, key, value)
272
273
274
275
    })
}

/// Returns the value stored under the given key in the contract's storage if any.
276
///
277
/// # Errors
278
///
Hero Bird's avatar
Hero Bird committed
279
280
/// - If the decoding of the typed value failed (`KeyNotFound`)
pub fn get_contract_storage<R>(key: &Key) -> Result<Option<R>>
281
282
283
284
where
    R: scale::Decode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
285
        EnvBackend::get_contract_storage::<R>(instance, key)
286
287
288
289
    })
}

/// Clears the contract's storage key entry.
290
pub fn clear_contract_storage(key: &Key) {
291
    <EnvInstance as OnInstance>::on_instance(|instance| {
292
        EnvBackend::clear_contract_storage(instance, key)
293
    })
Andrew Jones's avatar
Andrew Jones committed
294
295
}

296
/// Invokes a contract message.
297
///
298
299
300
301
302
303
304
305
306
/// # 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
307
308
/// - If the called account does not exist.
/// - If the called account is not a contract.
309
310
311
312
/// - 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.
313
pub fn invoke_contract<T, Args>(params: &CallParams<T, Args, ()>) -> Result<()>
314
where
315
    T: Environment,
316
    Args: scale::Encode,
317
{
318
    <EnvInstance as OnInstance>::on_instance(|instance| {
319
        TypedEnvBackend::invoke_contract::<T, Args>(instance, params)
320
    })
321
}
322

323
324
325
326
327
328
/// 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.
329
///
330
331
/// # Errors
///
Hero Bird's avatar
Hero Bird committed
332
333
/// - If the called account does not exist.
/// - If the called account is not a contract.
334
335
336
337
338
/// - 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.
339
pub fn eval_contract<T, Args, R>(params: &CallParams<T, Args, ReturnType<R>>) -> Result<R>
340
where
341
    T: Environment,
342
    Args: scale::Encode,
343
    R: scale::Decode,
344
{
345
    <EnvInstance as OnInstance>::on_instance(|instance| {
346
        TypedEnvBackend::eval_contract::<T, Args, R>(instance, params)
347
    })
348
349
}

350
351
352
353
354
355
/// 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.
356
///
357
358
359
360
361
362
363
364
/// # 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.
365
366
pub fn instantiate_contract<T, Args, Salt, C>(
    params: &CreateParams<T, Args, Salt, C>,
367
) -> Result<T::AccountId>
368
where
369
    T: Environment,
370
    Args: scale::Encode,
371
    Salt: AsRef<[u8]>,
372
{
373
    <EnvInstance as OnInstance>::on_instance(|instance| {
374
        TypedEnvBackend::instantiate_contract::<T, Args, Salt, C>(instance, params)
375
    })
376
}
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/// 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`.
409
///
410
411
412
413
/// The process of such a smart contract restoration can generally be very expensive.
///
/// # Note
///
414
/// - `filtered_keys` can be used to ignore certain storage regions
415
416
417
///   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.
418
/// - Restoration is canceled if there is no tombstone in the destination
419
420
421
///   address or if the hashes don't match. No changes are made in this case.
pub fn restore_contract<T>(
    account_id: T::AccountId,
422
    code_hash: T::Hash,
423
424
425
    rent_allowance: T::Balance,
    filtered_keys: &[Key],
) where
426
    T: Environment,
427
428
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
429
        TypedEnvBackend::restore_contract::<T>(
430
431
432
433
434
435
436
437
438
            instance,
            account_id,
            code_hash,
            rent_allowance,
            filtered_keys,
        )
    })
}

439
440
441
442
443
/// Terminates the existence of the currently executed smart contract.
///
/// This removes the calling account and transfers all remaining balance
/// to the given beneficiary.
///
444
445
/// No tombstone will be created, this function kills a contract completely!
///
446
447
448
449
/// # 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
450
/// which is considered fatal and results in a trap and rollback.
451
452
pub fn terminate_contract<T>(beneficiary: T::AccountId) -> !
where
453
    T: Environment,
454
455
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
456
        TypedEnvBackend::terminate_contract::<T>(instance, beneficiary)
457
458
459
    })
}

460
461
462
463
464
465
466
467
/// 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.
///
468
/// # Errors
469
///
470
/// - If the contract does not have sufficient funds.
471
/// - If the transfer had brought the sender's total balance below the
472
///   subsistence threshold.
473
474
pub fn transfer<T>(destination: T::AccountId, value: T::Balance) -> Result<()>
where
475
    T: Environment,
476
477
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
478
        TypedEnvBackend::transfer::<T>(instance, destination, value)
479
480
481
    })
}

482
/// Returns the execution input to the executed contract and decodes it as `T`.
483
484
485
486
487
///
/// # Note
///
/// - The input is the 4-bytes selector followed by the arguments
///   of the called function in their SCALE encoded representation.
488
489
490
491
492
493
/// - No prior interaction with the environment must take place before
///   calling this procedure.
///
/// # Usage
///
/// Normally contracts define their own `enum` dispatch types respective
494
495
/// to their exported constructors and messages that implement `scale::Decode`
/// according to the constructors or messages selectors and their arguments.
496
497
498
499
500
/// 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.
501
502
503
///
/// # Errors
///
504
505
506
507
508
/// If the given `T` cannot be properly decoded from the expected input.
pub fn decode_input<T>() -> Result<T>
where
    T: scale::Decode,
{
509
510
511
    <EnvInstance as OnInstance>::on_instance(|instance| {
        EnvBackend::decode_input::<T>(instance)
    })
512
513
514
515
516
517
}

/// Returns the value back to the caller of the executed contract.
///
/// # Note
///
Hero Bird's avatar
Hero Bird committed
518
519
/// This function  stops the execution of the contract immediately.
pub fn return_value<R>(return_flags: ReturnFlags, return_value: &R) -> !
520
521
522
523
where
    R: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
524
        EnvBackend::return_value::<R>(instance, return_flags, return_value)
525
526
527
    })
}

528
529
/// Returns a random hash seed and the block number since which it was determinable
/// by chain observers.
530
531
532
533
534
535
536
537
538
///
/// # 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.
539
540
541
542
543
544
545
546
547
///
/// # Important
///
/// The returned seed should only be used to distinguish commitments made before
/// the returned block number. If the block number is too early (i.e. commitments were
/// made afterwards), then ensure no further commitments may be made and repeatedly
/// call this on later blocks until the block number returned is later than the latest
/// commitment.
pub fn random<T>(subject: &[u8]) -> Result<(T::Hash, T::BlockNumber)>
548
where
549
    T: Environment,
550
551
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
552
        TypedEnvBackend::random::<T>(instance, subject)
553
554
555
    })
}

556
557
/// Appends the given message to the debug message buffer.
pub fn debug_message(message: &str) {
558
    <EnvInstance as OnInstance>::on_instance(|instance| {
559
        EnvBackend::debug_message(instance, message)
560
    })
561
562
}

563
564
565
566
567
568
569
570
571
/// 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)
    })
}
572

573
574
575
576
577
/// Conducts the crypto hash of the given encoded input and stores the result in `output`.
///
/// # Example
///
/// ```
578
/// # use ink_env::hash::{Sha2x256, HashOutput};
579
580
581
582
583
584
/// 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
585
/// ink_env::hash_encoded::<Sha2x256, _>(&encodable, &mut output);
586
587
588
589
590
591
592
593
594
595
/// 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)
    })
596
}