diff --git a/libraries/testing/contracts/eosio.bios/eosio.bios.abi b/libraries/testing/contracts/eosio.bios/eosio.bios.abi index 318202404f..e6597576a6 100644 --- a/libraries/testing/contracts/eosio.bios/eosio.bios.abi +++ b/libraries/testing/contracts/eosio.bios/eosio.bios.abi @@ -179,21 +179,25 @@ "type": "string" }, { - "name": "fweight", + "name": "weight", "type": "uint64" }, { - "name": "public_key_g1_affine_le", - "type": "bytes" + "name": "public_key", + "type": "string" + }, + { + "name": "pop", + "type": "string" } ] }, { - "name": "finalizer_set", + "name": "finalizer_policy", "base": "", "fields": [ { - "name": "fthreshold", + "name": "threshold", "type": "uint64" }, { @@ -395,12 +399,12 @@ ] }, { - "name": "setfinset", + "name": "setfinalizer", "base": "", "fields": [ { - "name": "fin_set", - "type": "finalizer_set" + "name": "finalizer_policy", + "type": "finalizer_policy" } ] }, @@ -550,8 +554,8 @@ "ricardian_contract": "" }, { - "name": "setfinset", - "type": "setfinset", + "name": "setfinalizer", + "type": "setfinalizer", "ricardian_contract": "" }, { diff --git a/libraries/testing/contracts/eosio.bios/eosio.bios.cpp b/libraries/testing/contracts/eosio.bios/eosio.bios.cpp index 068464f9dc..e0f5a9741b 100644 --- a/libraries/testing/contracts/eosio.bios/eosio.bios.cpp +++ b/libraries/testing/contracts/eosio.bios/eosio.bios.cpp @@ -1,9 +1,7 @@ #include "eosio.bios.hpp" +#include -extern "C" { - __attribute__((eosio_wasm_import)) - void set_finalizers( void* params, size_t params_size ); -}; +#include namespace eosiobios { @@ -22,6 +20,69 @@ void bios::setabi( name account, const std::vector& abi ) { } } +void bios::setfinalizer( const finalizer_policy& finalizer_policy ) { + // exensive checks are performed to make sure setfinalizer host function + // will never fail + + require_auth( get_self() ); + + check(finalizer_policy.finalizers.size() <= max_finalizers, "number of finalizers exceeds the maximum allowed"); + check(finalizer_policy.finalizers.size() > 0, "require at least one finalizer"); + + eosio::abi_finalizer_policy abi_finalizer_policy; + abi_finalizer_policy.fthreshold = finalizer_policy.threshold; + abi_finalizer_policy.finalizers.reserve(finalizer_policy.finalizers.size()); + + const std::string pk_prefix = "PUB_BLS"; + const std::string sig_prefix = "SIG_BLS"; + + // use raw affine format (bls_g1 is std::array) for uniqueness check + struct g1_hash { + std::size_t operator()(const eosio::bls_g1& g1) const { + std::hash hash_func; + return hash_func(g1.data()); + } + }; + struct g1_equal { + bool operator()(const eosio::bls_g1& lhs, const eosio::bls_g1& rhs) const { + return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0; + } + }; + std::unordered_set unique_finalizer_keys; + + uint64_t weight_sum = 0; + + for (const auto& f: finalizer_policy.finalizers) { + check(f.description.size() <= max_finalizer_description_size, "Finalizer description greater than max allowed size"); + + // basic key format checks + check(f.public_key.substr(0, pk_prefix.length()) == pk_prefix, "public key not started with PUB_BLS"); + check(f.pop.substr(0, sig_prefix.length()) == sig_prefix, "proof of possession signature not started with SIG_BLS"); + + // check overflow + check(std::numeric_limits::max() - weight_sum >= f.weight, "sum of weights causes uint64_t overflow"); + weight_sum += f.weight; + + // decode_bls_public_key_to_g1 will fail ("check" function fails) + // if the key is invalid + const auto pk = eosio::decode_bls_public_key_to_g1(f.public_key); + // duplicate key check + check(unique_finalizer_keys.insert(pk).second, "duplicate public key"); + + const auto signature = eosio::decode_bls_signature_to_g2(f.pop); + + // proof of possession of private key check + check(eosio::bls_pop_verify(pk, signature), "proof of possession failed"); + + std::vector pk_vector(pk.begin(), pk.end()); + abi_finalizer_policy.finalizers.emplace_back(eosio::abi_finalizer_authority{f.description, f.weight, std::move(pk_vector)}); + } + + check(finalizer_policy.threshold > weight_sum / 2, "finalizer policy threshold cannot be met by finalizer weights"); + + set_finalizers(std::move(abi_finalizer_policy)); +} + void bios::onerror( ignore, ignore> ) { check( false, "the onerror action cannot be called directly" ); } @@ -41,14 +102,6 @@ void bios::setprods( const std::vector& schedule ) { set_proposed_producers( schedule ); } -void bios::setfinset( const finalizer_set& fin_set ) { - require_auth( get_self() ); - - // until CDT provides a set_finalizers - auto packed_fin_set = eosio::pack( fin_set ); - set_finalizers((void*)packed_fin_set.data(), packed_fin_set.size()); -} - void bios::setparams( const eosio::blockchain_parameters& params ) { require_auth( get_self() ); set_blockchain_parameters( params ); @@ -61,7 +114,6 @@ void bios::reqauth( name from ) { void bios::activate( const eosio::checksum256& feature_digest ) { require_auth( get_self() ); preactivate_feature( feature_digest ); - print( "feature digest activated: ", feature_digest, "\n" ); } void bios::reqactivated( const eosio::checksum256& feature_digest ) { diff --git a/libraries/testing/contracts/eosio.bios/eosio.bios.hpp b/libraries/testing/contracts/eosio.bios/eosio.bios.hpp index 2f31ec64bc..4a02bcee83 100644 --- a/libraries/testing/contracts/eosio.bios/eosio.bios.hpp +++ b/libraries/testing/contracts/eosio.bios/eosio.bios.hpp @@ -5,27 +5,9 @@ #include #include #include +#include #include -/** - * EOSIO Contracts - * - * @details The design of the EOSIO blockchain calls for a number of smart contracts that are run at a - * privileged permission level in order to support functions such as block producer registration and - * voting, token staking for CPU and network bandwidth, RAM purchasing, multi-sig, etc. These smart - * contracts are referred to as the system, token, msig and wrap (formerly known as sudo) contracts. - * - * This repository contains examples of these privileged contracts that are useful when deploying, - * managing, and/or using an EOSIO blockchain. They are provided for reference purposes: - * - eosio.bios - * - eosio.system - * - eosio.msig - * - eosio.wrap - * - * The following unprivileged contract(s) are also part of the system. - * - eosio.token - */ - namespace eosiobios { using eosio::action_wrapper; @@ -36,14 +18,6 @@ namespace eosiobios { using eosio::permission_level; using eosio::public_key; - /** - * A weighted permission. - * - * @details Defines a weighted permission, that is a permission which has a weight associated. - * A permission is defined by an account name plus a permission name. The weight is going to be - * used against a threshold, if the weight is equal or greater than the threshold set then authorization - * will pass. - */ struct permission_level_weight { permission_level permission; uint16_t weight; @@ -52,11 +26,6 @@ namespace eosiobios { EOSLIB_SERIALIZE( permission_level_weight, (permission)(weight) ) }; - /** - * Weighted key. - * - * @details A weighted key is defined by a public key and an associated weight. - */ struct key_weight { eosio::public_key key; uint16_t weight; @@ -65,11 +34,6 @@ namespace eosiobios { EOSLIB_SERIALIZE( key_weight, (key)(weight) ) }; - /** - * Wait weight. - * - * @details A wait weight is defined by a number of seconds to wait for and a weight. - */ struct wait_weight { uint32_t wait_sec; uint16_t weight; @@ -78,15 +42,6 @@ namespace eosiobios { EOSLIB_SERIALIZE( wait_weight, (wait_sec)(weight) ) }; - /** - * Blockchain authority. - * - * @details An authority is defined by: - * - a vector of key_weights (a key_weight is a public key plus a weight), - * - a vector of permission_level_weights, (a permission_level is an account name plus a permission name) - * - a vector of wait_weights (a wait_weight is defined by a number of seconds to wait and a weight) - * - a threshold value - */ struct authority { uint32_t threshold = 0; std::vector keys; @@ -97,19 +52,6 @@ namespace eosiobios { EOSLIB_SERIALIZE( authority, (threshold)(keys)(accounts)(waits) ) }; - /** - * Blockchain block header. - * - * @details A block header is defined by: - * - a timestamp, - * - the producer that created it, - * - a confirmed flag default as zero, - * - a link to previous block, - * - a link to the transaction merkel root, - * - a link to action root, - * - a schedule version, - * - and a producers' schedule. - */ struct block_header { uint32_t timestamp; name producer; @@ -128,53 +70,45 @@ namespace eosiobios { /** * finalizer_authority * - * The public bls key of the hotstuff finalizer in Affine little-endian form. + * The public bls key and proof of possession of private key signature, + * and vote weight of a finalizer. */ + constexpr size_t max_finalizers = 64*1024; + constexpr size_t max_finalizer_description_size = 256; + struct finalizer_authority { - std::string description; - uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold - std::vector public_key_g1_affine_le; // size 96, CDT/abi_serializer has issues with std::array + std::string description; + uint64_t weight = 0; // weight that this finalizer's vote has for meeting threshold + std::string public_key; // public key of the finalizer in base64 format + std::string pop; // proof of possession of private key in base64 format - EOSLIB_SERIALIZE(finalizer_authority, (description)(fweight)(public_key_g1_affine_le)) + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE(finalizer_authority, (description)(weight)(public_key)(pop)) }; /** - * finalizer_set + * finalizer_policy * * List of finalizer authorties along with the threshold */ - struct finalizer_set { - uint64_t fthreshold = 0; + struct finalizer_policy { + uint64_t threshold = 0; // quorum threshold std::vector finalizers; - EOSLIB_SERIALIZE(finalizer_set, (fthreshold)(finalizers)); + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE(finalizer_policy, (threshold)(finalizers)); }; - /** - * @defgroup eosiobios eosio.bios - * @ingroup eosiocontracts - * - * eosio.bios is a minimalistic system contract that only supplies the actions that are absolutely - * critical to bootstrap a chain and nothing more. + * The `eosio.bios` is the first sample of system contract provided by `block.one` through the EOSIO platform. It is a minimalist system contract because it only supplies the actions that are absolutely critical to bootstrap a chain and nothing more. This allows for a chain agnostic approach to bootstrapping a chain. * - * @{ + * Just like in the `eosio.system` sample contract implementation, there are a few actions which are not implemented at the contract level (`newaccount`, `updateauth`, `deleteauth`, `linkauth`, `unlinkauth`, `canceldelay`, `onerror`, `setabi`, `setcode`), they are just declared in the contract so they will show in the contract's ABI and users will be able to push those actions to the chain via the account holding the `eosio.system` contract, but the implementation is at the EOSIO core level. They are referred to as EOSIO native actions. */ class [[eosio::contract("eosio.bios")]] bios : public eosio::contract { public: using contract::contract; /** - * @{ - * These actions map one-on-one with the ones defined in - * [Native Action Handlers](@ref native_action_handlers) section. - * They are present here so they can show up in the abi file and thus user can send them - * to this contract, but they have no specific implementation at this contract level, - * they will execute the implementation at the core level and nothing else. - */ - /** - * New account action - * - * @details Called after a new account is created. This code enforces resource-limits rules + * New account action, called after a new account is created. This code enforces resource-limits rules * for new accounts as well as new account naming conventions. * * 1. accounts cannot contain '.' symbols which forces all acccounts to be 12 @@ -191,9 +125,7 @@ namespace eosiobios { ignore owner, ignore active){} /** - * Update authorization action. - * - * @details Updates pemission for an account. + * Update authorization action updates pemission for an account. * * @param account - the account for which the permission is updated, * @param pemission - the permission name which is updated, @@ -207,9 +139,7 @@ namespace eosiobios { ignore auth ) {} /** - * Delete authorization action. - * - * @details Deletes the authorization for an account's permision. + * Delete authorization action deletes the authorization for an account's permission. * * @param account - the account for which the permission authorization is deleted, * @param permission - the permission name been deleted. @@ -219,9 +149,7 @@ namespace eosiobios { ignore permission ) {} /** - * Link authorization action. - * - * @details Assigns a specific action from a contract to a permission you have created. Five system + * Link authorization action assigns a specific action from a contract to a permission you have created. Five system * actions can not be linked `updateauth`, `deleteauth`, `linkauth`, `unlinkauth`, and `canceldelay`. * This is useful because when doing authorization checks, the EOSIO based blockchain starts with the * action needed to be authorized (and the contract belonging to), and looks up which permission @@ -242,9 +170,7 @@ namespace eosiobios { ignore requirement ) {} /** - * Unlink authorization action. - * - * @details It's doing the reverse of linkauth action, by unlinking the given action. + * Unlink authorization action it's doing the reverse of linkauth action, by unlinking the given action. * * @param account - the owner of the permission to be unlinked and the receiver of the freed RAM, * @param code - the owner of the action to be unlinked, @@ -256,9 +182,7 @@ namespace eosiobios { ignore type ) {} /** - * Cancel delay action. - * - * @details Cancels a deferred transaction. + * Cancel delay action cancels a deferred transaction. * * @param canceling_auth - the permission that authorizes this action, * @param trx_id - the deferred transaction id to be cancelled. @@ -267,9 +191,7 @@ namespace eosiobios { void canceldelay( ignore canceling_auth, ignore trx_id ) {} /** - * Set code action. - * - * @details Sets the contract code for an account. + * Set code action sets the contract code for an account. * * @param account - the account for which to set the contract code. * @param vmtype - reserved, set it to zero. @@ -279,12 +201,8 @@ namespace eosiobios { [[eosio::action]] void setcode( name account, uint8_t vmtype, uint8_t vmversion, const std::vector& code ) {} - /** @}*/ - /** - * Set abi for contract. - * - * @details Set the abi for contract identified by `account` name. Creates an entry in the abi_hash_table + * Set abi action sets the abi for contract identified by `account` name. Creates an entry in the abi_hash_table * index, with `account` name as key, if it is not already present and sets its value with the abi hash. * Otherwise it is updating the current abi hash value for the existing `account` key. * @@ -295,9 +213,7 @@ namespace eosiobios { void setabi( name account, const std::vector& abi ); /** - * On error action. - * - * @details Notification of this action is delivered to the sender of a deferred transaction + * On error action, notification of this action is delivered to the sender of a deferred transaction * when an objective error occurs while executing the deferred transaction. * This action is not meant to be called directly. * @@ -308,9 +224,16 @@ namespace eosiobios { void onerror( ignore sender_id, ignore> sent_trx ); /** - * Set privilege status for an account. + * Propose new finalizer policy that, unless superseded by a later + * finalizer policy, will eventually become the active finalizer policy. * - * @details Allows to set privilege status for an account (turn it on/off). + * @param finalizer_policy - proposed finalizer policy + */ + [[eosio::action]] + void setfinalizer( const finalizer_policy& finalizer_policy ); + + /** + * Set privilege action allows to set privilege status for an account (turn it on/off). * @param account - the account to set the privileged status for. * @param is_priv - 0 for false, > 0 for true. */ @@ -318,9 +241,7 @@ namespace eosiobios { void setpriv( name account, uint8_t is_priv ); /** - * Set the resource limits of an account - * - * @details Set the resource limits of an account + * Sets the resource limits of an account * * @param account - name of the account whose resource limit to be set * @param ram_bytes - ram limit in absolute bytes @@ -331,9 +252,7 @@ namespace eosiobios { void setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); /** - * Set a new list of active producers, that is, a new producers' schedule. - * - * @details Set a new list of active producers, by proposing a schedule change, once the block that + * Set producers action, sets a new list of active producers, by proposing a schedule change, once the block that * contains the proposal becomes irreversible, the schedule is promoted to "pending" * automatically. Once the block that promotes the schedule is irreversible, the schedule will * become "active". @@ -344,21 +263,7 @@ namespace eosiobios { void setprods( const std::vector& schedule ); /** - * Set a new list of finalizers. - * - * @details Set a new list of active finalizers, by proposing a finalizer set, once the block that - * contains the proposal becomes irreversible the new finalizer set will be made active according - * to Antelope finalizer active set rules. Replaces existing finalizer set. - * - * @param fin_et - New list of active finalizers to set - */ - [[eosio::action]] - void setfinset( const finalizer_set& fin_set ); - - /** - * Set the blockchain parameters - * - * @details Set the blockchain parameters. By tuning these parameters, various degrees of customization can be achieved. + * Set params action, sets the blockchain parameters. By tuning these parameters, various degrees of customization can be achieved. * * @param params - New blockchain parameters to set */ @@ -366,9 +271,7 @@ namespace eosiobios { void setparams( const eosio::blockchain_parameters& params ); /** - * Check if an account has authorization to access current action. - * - * @details Checks if the account name `from` passed in as param has authorization to access + * Require authorization action, checks if the account name `from` passed in as param has authorization to access * current action, that is, if it is listed in the action’s allowed permissions vector. * * @param from - the account name to authorize @@ -377,9 +280,7 @@ namespace eosiobios { void reqauth( name from ); /** - * Activates a protocol feature. - * - * @details Activates a protocol feature + * Activate action, activates a protocol feature * * @param feature_digest - hash of the protocol feature to activate. */ @@ -387,20 +288,13 @@ namespace eosiobios { void activate( const eosio::checksum256& feature_digest ); /** - * Asserts that a protocol feature has been activated. - * - * @details Asserts that a protocol feature has been activated + * Require activated action, asserts that a protocol feature has been activated * * @param feature_digest - hash of the protocol feature to check for activation. */ [[eosio::action]] void reqactivated( const eosio::checksum256& feature_digest ); - /** - * Abi hash structure - * - * @details Abi hash structure is defined by contract owner and the contract hash. - */ struct [[eosio::table]] abi_hash { name owner; checksum256 hash; @@ -409,9 +303,6 @@ namespace eosiobios { EOSLIB_SERIALIZE( abi_hash, (owner)(hash) ) }; - /** - * Multi index table that stores the contracts' abi index by their owners/accounts. - */ typedef eosio::multi_index< "abihash"_n, abi_hash > abi_hash_table; using newaccount_action = action_wrapper<"newaccount"_n, &bios::newaccount>; @@ -425,11 +316,9 @@ namespace eosiobios { using setpriv_action = action_wrapper<"setpriv"_n, &bios::setpriv>; using setalimits_action = action_wrapper<"setalimits"_n, &bios::setalimits>; using setprods_action = action_wrapper<"setprods"_n, &bios::setprods>; - using setfinset_action = action_wrapper<"setfinset"_n, &bios::setfinset>; using setparams_action = action_wrapper<"setparams"_n, &bios::setparams>; using reqauth_action = action_wrapper<"reqauth"_n, &bios::reqauth>; using activate_action = action_wrapper<"activate"_n, &bios::activate>; using reqactivated_action = action_wrapper<"reqactivated"_n, &bios::reqactivated>; }; - /** @}*/ // end of @defgroup eosiobios eosio.bios -} /// namespace eosiobios +} \ No newline at end of file diff --git a/libraries/testing/contracts/eosio.bios/eosio.bios.wasm b/libraries/testing/contracts/eosio.bios/eosio.bios.wasm index b8c7ad3d82..92e6bec8f6 100755 Binary files a/libraries/testing/contracts/eosio.bios/eosio.bios.wasm and b/libraries/testing/contracts/eosio.bios/eosio.bios.wasm differ