api.rs 15.5 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
//! The public raw interface towards the host Wasm engine.
Hero Bird's avatar
Hero Bird committed
16

17 18 19 20 21 22 23 24 25 26 27 28 29 30
use crate::env::{
    backend::{
        Env,
        TypedEnv,
    },
    call::{
        CallData,
        CallParams,
        InstantiateParams,
        ReturnType,
    },
    engine::{
        EnvInstance,
        OnInstance,
31
    },
32 33 34
    EnvTypes,
    Result,
    Topics,
35
};
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| TypedEnv::caller::<T>(instance))
}

/// 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::transferred_balance::<T>(instance)
    })
}

/// Returns the current price for gas.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn gas_price<T>() -> Result<T::Balance>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::gas_price::<T>(instance)
    })
}

/// 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| TypedEnv::gas_left::<T>(instance))
}

/// Returns the current block timestamp.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn block_timestamp<T>() -> Result<T::Timestamp>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::block_timestamp::<T>(instance)
    })
}
103

104
/// Returns the account ID of the executed contract.
105
///
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
/// # 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::account_id::<T>(instance)
    })
}

/// Returns the balance of the executed contract.
///
/// # Errors
125
///
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/// If the returned value cannot be properly decoded.
pub fn balance<T>() -> Result<T::Balance>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| TypedEnv::balance::<T>(instance))
}

/// 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::rent_allowance::<T>(instance)
    })
146 147
}

148
/// Returns the current block number.
149
///
150
/// # Errors
151
///
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
/// If the returned value cannot be properly decoded.
pub fn block_number<T>() -> Result<T::BlockNumber>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::block_number::<T>(instance)
    })
}

/// Returns the minimum balance for the contracts chain.
///
/// # Errors
///
/// If the returned value cannot be properly decoded.
pub fn minimum_balance<T>() -> Result<T::Balance>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::minimum_balance::<T>(instance)
    })
}

/// 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::tombstone_deposit::<T>(instance)
    })
}

/// Emits an event with the given event data.
pub fn emit_event<T, Event>(event: Event)
where
    T: EnvTypes,
    Event: Topics<T> + scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::emit_event::<T, Event>(instance, event)
    })
199 200
}

201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
/// Sets the rent allowance of the executed contract to the new value.
pub fn set_rent_allowance<T>(new_value: T::Balance)
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::set_rent_allowance::<T>(instance, new_value)
    })
}

/// Writes the value to the contract storage under the given key.
pub fn set_contract_storage<V>(key: Key, value: &V)
where
    V: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        Env::set_contract_storage::<V>(instance, key, value)
    })
}

/// Returns the value stored under the given key in the contract's storage if any.
222
///
223
/// # Errors
224
///
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
/// - If the decoding of the typed value failed
pub fn get_contract_storage<R>(key: Key) -> Option<Result<R>>
where
    R: scale::Decode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        Env::get_contract_storage::<R>(instance, key)
    })
}

/// Clears the contract's storage key entry.
pub fn clear_contract_storage(key: Key) {
    <EnvInstance as OnInstance>::on_instance(|instance| {
        Env::clear_contract_storage(instance, key)
    })
Andrew Jones's avatar
Andrew Jones committed
240 241
}

242
/// Invokes a call to the runtime.
Andrew Jones's avatar
Andrew Jones committed
243
///
244
/// # Note
Andrew Jones's avatar
Andrew Jones committed
245
///
246 247 248 249 250 251 252
/// The call is not guaranteed to execute immediately but might be deferred
/// to the end of the contract execution.
///
/// # Errors
///
/// - If the called runtime function does not exist.
pub fn invoke_runtime<T>(params: &T::Call) -> Result<()>
Andrew Jones's avatar
Andrew Jones committed
253
where
254
    T: EnvTypes,
Andrew Jones's avatar
Andrew Jones committed
255
{
256 257 258
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::invoke_runtime::<T>(instance, params)
    })
259
}
260

261
/// Invokes a contract message.
262
///
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
/// # 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
///
/// - If the called contract does not exist.
/// - 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.
pub fn invoke_contract<T>(params: &CallParams<T, ()>) -> Result<()>
278
where
279
    T: EnvTypes,
280
{
281 282 283
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::invoke_contract::<T>(instance, params)
    })
284
}
285

286 287 288 289 290 291
/// 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.
292
///
293 294 295 296 297 298 299 300 301
/// # Errors
///
/// - If the called contract does not exist.
/// - 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.
pub fn eval_contract<T, R>(params: &CallParams<T, ReturnType<R>>) -> Result<R>
302
where
303 304
    T: EnvTypes,
    R: scale::Decode,
305
{
306 307 308
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::eval_contract::<T, R>(instance, params)
    })
309 310
}

311 312 313 314 315 316
/// 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.
317
///
318 319 320 321 322 323 324 325 326 327 328
/// # 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.
pub fn instantiate_contract<T, C>(
    params: &InstantiateParams<T, C>,
) -> Result<T::AccountId>
329
where
330
    T: EnvTypes,
331
{
332 333 334
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::instantiate_contract::<T, 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
/// 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`.
368
///
369 370 371 372 373 374 375 376 377 378 379 380
/// The process of such a smart contract restoration can generally be very expensive.
///
/// # Note
///
/// - The `filtered_keys` can be used to ignore certain storage regions
///   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,
381
    code_hash: T::Hash,
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
    rent_allowance: T::Balance,
    filtered_keys: &[Key],
) where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::restore_contract::<T>(
            instance,
            account_id,
            code_hash,
            rent_allowance,
            filtered_keys,
        )
    })
}

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
/// 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
/// which is considered fatal and results in a trap + rollback.
pub fn terminate_contract<T>(beneficiary: T::AccountId) -> !
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::terminate_contract::<T>(instance, beneficiary)
    })
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
/// 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.
///
/// # Errors
///
/// If the contract doesn't have sufficient funds.
pub fn transfer<T>(destination: T::AccountId, value: T::Balance) -> Result<()>
where
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::transfer::<T>(instance, destination, value)
    })
}

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
/// Returns the input to the executed contract.
///
/// # Note
///
/// - The input is the 4-bytes selector followed by the arguments
///   of the called function in their SCALE encoded representation.
/// - This property must be received as the first action an executed
///   contract to its environment and can only be queried once.
///   The environment access asserts this guarantee.
///
/// # Errors
///
/// - If the call to `input` is not the first call to the environment.
/// - If the input failed to decode into call data.
///     - This happens only if the host runtime provides less than 4 bytes for
///       the function selector upon this query.
pub fn input() -> Result<CallData> {
    <EnvInstance as OnInstance>::on_instance(|instance| Env::input(instance))
}

/// Returns the value back to the caller of the executed contract.
///
/// # Note
///
/// This call must be the last call to the contract
/// environment for every contract execution.
pub fn output<R>(return_value: &R)
where
    R: scale::Encode,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        Env::output::<R>(instance, return_value)
    })
}

/// 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
    T: EnvTypes,
{
    <EnvInstance as OnInstance>::on_instance(|instance| {
        TypedEnv::random::<T>(instance, subject)
    })
}

/// Prints the given contents to the environmental log.
pub fn println(content: &str) {
    <EnvInstance as OnInstance>::on_instance(|instance| Env::println(instance, content))
}

/// Returns the value from the *runtime* storage at the position of the key if any.
///
/// # Errors
///
/// - If the decoding of the typed value failed
pub fn get_runtime_storage<R>(runtime_key: &[u8]) -> Option<Result<R>>
502
where
503
    R: scale::Decode,
504
{
505 506 507
    <EnvInstance as OnInstance>::on_instance(|instance| {
        Env::get_runtime_storage::<R>(instance, runtime_key)
    })
508
}
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526

/// Built-in efficient cryptographic hash functions.
pub mod hash {
    use super::*;

    macro_rules! impl_hash_fn {
        ( $(#[$doc:meta])* fn $name:ident($output_len:literal) ) => {
            paste::item! {
                $( #[$doc] )*
                pub fn $name(input: &[u8], output: &mut [u8; $output_len]) {
                    // No need to actually access the environmental instance
                    // if we only call one of its inherent methods.
                    <EnvInstance as Env>::[<hash_ $name>](input, output)
                }
            }
        };
    }
    impl_hash_fn!(
527
        /// Conducts the SHA2 256-bit hash of the given bytes and
528 529 530 531
        /// puts the result into the output buffer.
        fn sha2_256(32)
    );
    impl_hash_fn!(
532
        /// Conducts the KECCAK 256-bit hash of the given bytes and
533 534 535 536
        /// puts the result into the output buffer.
        fn keccak_256(32)
    );
    impl_hash_fn!(
537
        /// Conducts the BLAKE2 256-bit hash of the given bytes and
538 539 540 541
        /// puts the result into the output buffer.
        fn blake2_256(32)
    );
    impl_hash_fn!(
542
        /// Conducts the BLAKE2 128-bit hash of the given bytes and
543 544 545 546
        /// puts the result into the output buffer.
        fn blake2_128(16)
    );
}