8 EOSIO WASM intrinsics you might not have heard about

in #eos5 years ago

8 EOSIO WASM intrinsics you might not have heard about

<p dir="auto">EOSIO smart contracts are just simple WebAssembly files.<br /> The WebAssembly format allows defining <strong>imports, functions that are not declared in WASM itself but in the environment the WebAssembly code is executed in.<br /> EOSIO makes use of these builtin functions (<a href="https://en.wikipedia.org/wiki/Intrinsic_function" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">intrinsics) to exchange data between the WebAssembly contract code and the EOSIO <code>nodeos node.<br /> Whenever the EOS virtual machine (EOSVM), which executes the WebAssembly code, hits such an intrinsic the program control is handed over to the <em>nodeos controller code to resolve it.<br /> A full list of intrinsics as of EOSIO 2.0.X <a href="https://github.com/EOSIO/eosio.cdt/blob/a6b8d3fc289d46f4612588cdd7223a3d549238f6/libraries/native/native/eosio/intrinsics_def.hpp#L42-L160" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">can be found here: <pre><code>get_resource_limits set_resource_limits set_proposed_producers set_proposed_producers_ex get_blockchain_parameters_packed set_blockchain_parameters_packed is_privileged set_privileged is_feature_activated preactivate_feature get_active_producers db_idx64_store db_idx64_remove db_idx64_update db_idx64_find_primary db_idx64_find_secondary db_idx64_lowerbound db_idx64_upperbound db_idx64_end db_idx64_next db_idx64_previous db_idx128_store db_idx128_remove db_idx128_update db_idx128_find_primary db_idx128_find_secondary db_idx128_lowerbound db_idx128_upperbound db_idx128_end db_idx128_next db_idx128_previous db_idx256_store db_idx256_remove db_idx256_update db_idx256_find_primary db_idx256_find_secondary db_idx256_lowerbound db_idx256_upperbound db_idx256_end db_idx256_next db_idx256_previous db_idx_double_store db_idx_double_remove db_idx_double_update db_idx_double_find_primary db_idx_double_find_secondary db_idx_double_lowerbound db_idx_double_upperbound db_idx_double_end db_idx_double_next db_idx_double_previous db_idx_long_double_store db_idx_long_double_remove db_idx_long_double_update db_idx_long_double_find_primary db_idx_long_double_find_secondary db_idx_long_double_lowerbound db_idx_long_double_upperbound db_idx_long_double_end db_idx_long_double_next db_idx_long_double_previous db_store_i64 db_update_i64 db_remove_i64 db_get_i64 db_next_i64 db_previous_i64 db_find_i64 db_lowerbound_i64 db_upperbound_i64 db_end_i64 assert_recover_key recover_key assert_sha256 assert_sha1 assert_sha512 assert_ripemd160 sha1 sha256 sha512 ripemd160 check_transaction_authorization check_permission_authorization get_permission_last_used get_account_creation_time current_time publication_time read_action_data action_data_size current_receiver require_recipient require_auth require_auth2 has_auth is_account prints prints_l printi printui printi128 printui128 printsf printdf printqf printn printhex read_transaction transaction_size expiration tapos_block_prefix tapos_block_num get_action send_inline send_context_free_inline send_deferred cancel_deferred get_context_free_data get_sender <p dir="auto">This list is not fixed, it evolves with EOSIO. For example, EOSIO 1.8 introduced the <code>get_sender intrinsic.<br /> There are also talks about including intrinsics for Elliptic Curve Cryptography in a future EOSIO release. <p dir="auto">Most of the intrinsics are commonly used by EOSIO smart contract developers, but there are a few that are not widely known and are rarely used.<br /> Let's look at 8 EOSIO intrinsics you might not have heard about before: <ol> <li><code>publication_time: Returns the transaction's publication time. <pre><code>time_point publication = eosio::publication_time(); <li><code>get_account_creation_time: Returns the account creation time. This could be useful if you implement an airgrab and only want all accounts older than some specific date to be eligible. Alternatively, it could be used in a voting strength calculation - older accounts have more power. <pre><code>time_point creation_time = get_account_creation_time(get_self()); <li><code>get_permission_last_used: Returns the date when an account's permission was used the last time. Could be used to check for dormant accounts. However, you need to specify a specific permission and EOSIO allows you to define custom permissions, which means it won't give you an accurate prediction of when an account authorized an action the last time. <pre><code>time_point last_used = get_permission_last_used(get_self(), name("active")); <li><code>is_feature_activated: EOSIO is constantly developing and not all chains run the latest version. Furthermore, EOSIO 1.8 introduced <em>feature flags where BPs can decide to enable or disable a specific feature. The <code>is_feature_activated intrinsic allows smart contract developers to write chain-independent code with different behavior depending on what features are activated. For example, we could check if the <code>get_sender intrinsic is activated. <pre><code>// GET_SENDER = hex f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d const checksum256 &feature_digest = ...; bool activated = eosio::is_feature_activated(feature_digest); name sender = activated ? name(eosio::get_sender()); : get_first_receiver(); <li><code>get_sender: This intrinsic allows getting the actual sender of an inline action or action notification. It can be used to forbid smart contracts from calling actions on your smart contract. Something that <a href="https://cmichel.io/how-to-check-if-an-eos-account-has-a-smart-contract/" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">NewDex tries to achieve, but is currently easy to circumvent with custom permissions. <pre><code>name sender = name(eosio::get_sender()); <li><code>read_transaction: This is one of the must useful unknown intrinsics in my opinion. It returns the <strong>input transaction. Meaning, you'll get access to the transaction header and actions that are defined in the transaction that was submitted to the chain. Actions that are the result of inline actions or <code>require_recipient calls are <em>not included. Usecases are checking who paid for CPU of the transaction, or checking for transactions that consist of multiple actions, like a token <code>open + transfer transaction. <pre><code>char tx_buffer[eosio::transaction_size()]; eosio::read_transaction(tx_buffer, eosio::transaction_size()); const std::vector<char> trx_vector( tx_buffer, tx_buffer + sizeof tx_buffer / sizeof tx_buffer[0]); transaction trx = eosio::unpack<transaction>(trx_vector); action first_action = trx.actions[0]; print("first action was: ", first_action.account, " ", first_action.name); char *action_data_buffer = trx.actions.at(0).data.data(); <li><code>check_permission_authorization: Allows to check if an account's permission is satisfied by specific public keys, accounts, or waits. <pre><code>ACTION permissionpm(const eosio::public_key &pub) { const std::set<public_key> provided_keys = {pub}; // check_permission_authorization actually returns a boolean check(check_permission_authorization(get_self(), name("active"), provided_keys), "please add this key to the active permission"); } <li><code>check_transaction_authorization: Similar to the previous <code>check_permission_authorization, it checks if all declared authorizations of all actions of the specified transaction are satisfied by a set of provided permissions. Note that this does not check signatures of the transaction and the provided public keys though. I can't think of any usecases for the average EOSIO smart contract. This might still be useful when implementing a utility smart contract that serializes transactions on-chain and provides an alternative to deferred transactions. <pre><code>ACTION permissiontx(const transaction &tx) { std::set<permission_level> provided_permissions = { permission_level(get_self(), eosio::name("dummy"))}; const std::set<public_key> provided_keys; // check_transaction_authorization actually returns a boolean check(check_transaction_authorization(tx, provided_permissions, provided_keys), "wrong auth"); } <p dir="auto">Have you ever used one of these intrinsics? I'd be curious to discover new use-cases for these. <p dir="auto"><a href="https://learneos.dev#modal" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://cmichel.io/images/learneos_subscribe.png" alt="Learn EOS Development Signup" srcset="https://images.hive.blog/768x0/https://cmichel.io/images/learneos_subscribe.png 1x, https://images.hive.blog/1536x0/https://cmichel.io/images/learneos_subscribe.png 2x" /> <hr /> <p dir="auto">Originally published at <a href="https://cmichel.io/eosio-wasm-intrinsics-you-might-not-have-heard-about/" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://cmichel.io/eosio-wasm-intrinsics-you-might-not-have-heard-about/