Context API

Context API mostly provides read-only functions that access current information about the blockchain, the accounts (that originally initiated the chain of cross-contract calls, the immediate contract that called the current one, the account of the current contract), other important information like storage usage.

Many of the below functions are currently implemented through data_read which allows to read generic context data. However, there is no reason to have data_read instead of the specific functions:

  • data_read does not solve forward compatibility. If later we want to add another context function, e.g. executed_operations we can just declare it as a new function, instead of encoding it as DATA_TYPE_EXECUTED_OPERATIONS = 42 which is passed as the first argument to data_read;
  • data_read does not help with renaming. If later we decide to rename signer_account_id to originator_id then one could argue that contracts that rely on data_read would not break, while contracts relying on signer_account_id() would. However the name change often means the change of the semantics, which means the contracts using this function are no longer safe to execute anyway.

However there is one reason to not have data_read -- it makes API more human-like which is a general direction Wasm APIs, like WASI are moving towards to.



#![allow(unused)]
fn main() {
current_account_id(register_id: u64)
}

Saves the account id of the current contract that we execute into the register.

Panics
  • If the registers exceed the memory limit panics with MemoryAccessViolation;


#![allow(unused)]
fn main() {
signer_account_id(register_id: u64)
}

All contract calls are a result of some transaction that was signed by some account using some access key and submitted into a memory pool (either through the wallet using RPC or by a node itself). This function returns the id of that account.

Normal operation
  • Saves the bytes of the signer account id into the register.
Panics
  • If the registers exceed the memory limit panics with MemoryAccessViolation;
  • If called in a view function panics with ProhibitedInView.
Current bugs
  • Currently we conflate originator_id and sender_id in our code base.


#![allow(unused)]
fn main() {
signer_account_pk(register_id: u64)
}

Saves the public key fo the access key that was used by the signer into the register. In rare situations smart contract might want to know the exact access key that was used to send the original transaction, e.g. to increase the allowance or manipulate with the public key.

Panics
  • If the registers exceed the memory limit panics with MemoryAccessViolation;
  • If called in a view function panics with ProhibitedInView.
Current bugs
  • Not implemented.


#![allow(unused)]
fn main() {
predecessor_account_id(register_id: u64)
}

All contract calls are a result of a receipt, this receipt might be created by a transaction that does function invocation on the contract or another contract as a result of cross-contract call.

Normal operation
  • Saves the bytes of the predecessor account id into the register.
Panics
  • If the registers exceed the memory limit panics with MemoryAccessViolation;
  • If called in a view function panics with ProhibitedInView.
Current bugs
  • Not implemented.


#![allow(unused)]
fn main() {
input(register_id: u64)
}

Reads input to the contract call into the register. Input is expected to be in JSON-format.

Normal operation
  • If input is provided saves the bytes (potentially zero) of input into register.
  • If input is not provided does not modify the register.
Returns
  • If input was not provided returns 0;
  • If input was provided returns 1; If input is zero bytes returns 1, too.
Panics
  • If the registers exceed the memory limit panics with MemoryAccessViolation;
Current bugs
  • Implemented as part of data_read. However there is no reason to have one unified function, like data_read that can be used to read all


#![allow(unused)]
fn main() {
block_index() -> u64
}

Returns the current block height from genesis.



#![allow(unused)]
fn main() {
block_timestamp() -> u64
}

Returns the current block timestamp (number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC).



#![allow(unused)]
fn main() {
epoch_height() -> u64
}

Returns the current epoch height from genesis.



#![allow(unused)]
fn main() {
storage_usage() -> u64
}

Returns the number of bytes used by the contract if it was saved to the trie as of the invocation. This includes:

  • The data written with storage_* functions during current and previous execution;
  • The bytes needed to store the account protobuf and the access keys of the given account.