From b5fad7be0f8e40fdebe994ab7709b675e91dd773 Mon Sep 17 00:00:00 2001 From: Zach <34947245+kj4ezj@users.noreply.github.com> Date: Tue, 2 Apr 2019 16:13:16 -0400 Subject: [PATCH 001/106] Added contracts pipeline dependencies (#219) --- dependencies | 3 +++ docker/buildContracts.sh | 5 +++++ docker/environment.dockerpart | 3 +++ docker/external-dependencies.dockerpart | 4 ++++ docker/unit-test.sh | 10 ++++++++++ docker/verifyInstallation.sh | 11 +++++++++++ 6 files changed, 36 insertions(+) create mode 100644 dependencies create mode 100755 docker/buildContracts.sh create mode 100644 docker/environment.dockerpart create mode 100644 docker/external-dependencies.dockerpart create mode 100755 docker/unit-test.sh create mode 100755 docker/verifyInstallation.sh diff --git a/dependencies b/dependencies new file mode 100644 index 000000000..e70223ba5 --- /dev/null +++ b/dependencies @@ -0,0 +1,3 @@ +# dependencies to pull for a build of contracts, by branch, tag, or commit hash +eosio=release/1.7.x +cdt=release/1.5.x diff --git a/docker/buildContracts.sh b/docker/buildContracts.sh new file mode 100755 index 000000000..8d63f7598 --- /dev/null +++ b/docker/buildContracts.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd /eosio.contracts +./build.sh +cd build +tar -pczf /artifacts/contracts.tar.gz * diff --git a/docker/environment.dockerpart b/docker/environment.dockerpart new file mode 100644 index 000000000..cde89d508 --- /dev/null +++ b/docker/environment.dockerpart @@ -0,0 +1,3 @@ +# set environment variables (EOSIO_ROOT and CMAKE_FRAMEWORK_PATH are autogenerated) +RUN PATH=/usr/local/eosio/bin:$(echo "/usr/opt/eosio.cdt/$(ls /usr/opt/eosio.cdt)/bin"):$PATH +ENV LD_LIBRARY_PATH=/usr/local/lib \ No newline at end of file diff --git a/docker/external-dependencies.dockerpart b/docker/external-dependencies.dockerpart new file mode 100644 index 000000000..f2e272752 --- /dev/null +++ b/docker/external-dependencies.dockerpart @@ -0,0 +1,4 @@ +# install external dependencies +RUN apt-get update && \ +apt-get -y upgrade && \ +DEBIAN_FRONTEND=noninteractive apt-get -y install openssl ca-certificates build-essential libbz2-dev zlib1g-dev libssl-dev libgmp3-dev libicu-dev cmake bc jq curl wget net-tools unzip gnupg git graphviz \ No newline at end of file diff --git a/docker/unit-test.sh b/docker/unit-test.sh new file mode 100755 index 000000000..25d98b645 --- /dev/null +++ b/docker/unit-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e # exit on failure of any "simple" command (excludes &&, ||, or | chains) +CPU_CORES=$(getconf _NPROCESSORS_ONLN) +echo "$CPU_CORES cpu cores detected." +cd /eosio.contracts/build/tests +TEST_COUNT=$(ctest -N | grep -i 'Total Tests: ' | cut -d ':' -f 2 | awk '{print $1}') +[[ $TEST_COUNT > 0 ]] && echo "$TEST_COUNT tests found." || (echo "ERROR: No tests registered with ctest! Exiting..." && exit 1) +echo "$ ctest -j $CPU_CORES --output-on-failure -T Test" +ctest -j $CPU_CORES --output-on-failure -T Test +mv /eosio.contracts/build/tests/Testing/$(ls /eosio.contracts/build/tests/Testing/ | grep '20' | tail -n 1)/Test.xml /artifacts/Test.xml \ No newline at end of file diff --git a/docker/verifyInstallation.sh b/docker/verifyInstallation.sh new file mode 100755 index 000000000..37fcb5296 --- /dev/null +++ b/docker/verifyInstallation.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# expected places to find EOSIO CMAKE in the docker container, in ascending order of preference +[[ -e /usr/lib/eosio/lib/cmake/eosio/eosio-config.cmake ]] && export CMAKE_FRAMEWORK_PATH="/usr/lib/eosio" +[[ -e /opt/eosio/lib/cmake/eosio/eosio-config.cmake ]] && export CMAKE_FRAMEWORK_PATH="/opt/eosio" +[[ ! -z "$EOSIO_ROOT" && -e $EOSIO_ROOT/lib/cmake/eosio/eosio-config.cmake ]] && export CMAKE_FRAMEWORK_PATH="$EOSIO_ROOT" +# fail if we didn't find it +[[ -z "$CMAKE_FRAMEWORK_PATH" ]] && exit 1 +# export variables +echo "" >> /eosio.contracts/docker/environment.Dockerfile # necessary if there is no '\n' at end of file +echo "ENV CMAKE_FRAMEWORK_PATH=$CMAKE_FRAMEWORK_PATH" >> /eosio.contracts/docker/environment.Dockerfile +echo "ENV EOSIO_ROOT=$CMAKE_FRAMEWORK_PATH" >> /eosio.contracts/docker/environment.Dockerfile \ No newline at end of file From a3ae9f1581f16734adeee8de7427040d15f756da Mon Sep 17 00:00:00 2001 From: EOS Authority <38717729+eosauthority@users.noreply.github.com> Date: Mon, 29 Apr 2019 15:02:48 +0100 Subject: [PATCH 002/106] Missed defnetloan added --- contracts/eosio.system/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/README.md b/contracts/eosio.system/README.md index 9e8c0fa63..35a64c80e 100755 --- a/contracts/eosio.system/README.md +++ b/contracts/eosio.system/README.md @@ -159,8 +159,8 @@ The naming convention is codeaccount::actionname followed by a list of paramters - **loan_num** loan id - **amount** tokens transfered from CPU loan fund to REX fund -## eosio::defcpuloan from loan\_num amount - - Withdraws tokens from the fund of a specific CPU loan and adds them to REX fund +## eosio::defnetloan from loan\_num amount + - Withdraws tokens from the fund of a specific NET loan and adds them to REX fund - **from** loan creator account - **loan_num** loan id - **amount** tokens transfered from NET loan fund to REX fund From 79f33c0846e577969d3b10f88869c08bfeb7f54d Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Tue, 30 Apr 2019 14:24:15 -0400 Subject: [PATCH 003/106] Created universal pipeline configuration file --- dependencies | 3 --- pipeline.jsonc | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) delete mode 100644 dependencies create mode 100644 pipeline.jsonc diff --git a/dependencies b/dependencies deleted file mode 100644 index 94801f14a..000000000 --- a/dependencies +++ /dev/null @@ -1,3 +0,0 @@ -# dependencies to pull for a build of contracts, by branch, tag, or commit hash -eosio=release/1.8.x -cdt=release/1.6.x diff --git a/pipeline.jsonc b/pipeline.jsonc new file mode 100644 index 000000000..28912b072 --- /dev/null +++ b/pipeline.jsonc @@ -0,0 +1,11 @@ +{ + "eosio-dot-contracts": + { + "pipeline-branch": "master", + "dependencies": // dependencies to pull for a build of contracts, by branch, tag, or commit hash + { + "eosio": "release/1.8.x", + "eosio.cdt": "release/1.6.x" + } + } +} \ No newline at end of file From 9fcab428cd74cec71ff72abc4d0606c9b14539fe Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Tue, 30 Apr 2019 14:27:44 -0400 Subject: [PATCH 004/106] Created Universal Pipeline Configuration File --- dependencies | 3 --- pipeline.jsonc | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) delete mode 100644 dependencies create mode 100644 pipeline.jsonc diff --git a/dependencies b/dependencies deleted file mode 100644 index e70223ba5..000000000 --- a/dependencies +++ /dev/null @@ -1,3 +0,0 @@ -# dependencies to pull for a build of contracts, by branch, tag, or commit hash -eosio=release/1.7.x -cdt=release/1.5.x diff --git a/pipeline.jsonc b/pipeline.jsonc new file mode 100644 index 000000000..17718d967 --- /dev/null +++ b/pipeline.jsonc @@ -0,0 +1,11 @@ +{ + "eosio-dot-contracts": + { + "pipeline-branch": "master", + "dependencies": // dependencies to pull for a build of contracts, by branch, tag, or commit hash + { + "eosio": "release/1.7.x", + "eosio.cdt": "release/1.5.x" + } + } +} \ No newline at end of file From 3b47a4a17e6fc427e4e1b3126240d41dc43e975b Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 17 Jun 2019 14:10:28 -0400 Subject: [PATCH 005/106] Fix wrong assertion in create_core_token (adapted from @elmato's commit d8b9e9666b33a6ca3e2dce3baec21afc410de3c6) --- tests/eosio.system_tester.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 68baec76f..657ce487c 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -52,7 +52,7 @@ class eosio_system_tester : public TESTER { } void create_core_token( symbol core_symbol = symbol{CORE_SYM} ) { - FC_ASSERT( core_symbol.precision() != 4, "create_core_token assumes precision of core token is 4" ); + FC_ASSERT( core_symbol.decimals() == 4, "create_core_token assumes core token has 4 digits of precision" ); create_currency( N(eosio.token), config::system_account_name, asset(100000000000000, core_symbol) ); issue( asset(10000000000000, core_symbol) ); BOOST_REQUIRE_EQUAL( asset(10000000000000, core_symbol), get_balance( "eosio", core_symbol ) ); From 8f3777290740dd59fc61966d203a5e0bec4d6ca6 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 17 Jun 2019 14:37:25 -0400 Subject: [PATCH 006/106] cleanup extraneous and inconsistent license references --- .../include/eosio.system/eosio.system.hpp | 4 -- .../include/eosio.system/native.hpp | 72 +++++++++---------- .../eosio.system/src/delegate_bandwidth.cpp | 8 +-- contracts/eosio.system/src/rex.cpp | 16 ++--- contracts/eosio.system/src/voting.cpp | 4 -- .../include/eosio.token/eosio.token.hpp | 60 ++++++++-------- contracts/eosio.token/src/eosio.token.cpp | 5 -- tests/eosio.system_tester.hpp | 4 -- 8 files changed, 70 insertions(+), 103 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4e40ad41e..14c2f383d 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index 5d77d256c..e197485b1 100755 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include @@ -52,9 +48,9 @@ namespace eosiosystem { * @{ */ /** - * A weighted permission. - * - * @details Defines a weighted permission, that is a permission which has a weight associated. + * 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. */ struct permission_level_weight { @@ -67,7 +63,7 @@ namespace eosiosystem { /** * Weighted key. - * + * * @details A weighted key is defined by a public key and an associated weight. */ struct key_weight { @@ -80,7 +76,7 @@ namespace eosiosystem { /** * Wait weight. - * + * * @details A wait weight is defined by a number of seconds to wait for and a weight. */ struct wait_weight { @@ -93,7 +89,7 @@ namespace eosiosystem { /** * Blockchain authority. - * + * * @details An authority is defined by: * - a vector of key_weights (a key_weight is a public key plus a wieght), * - a vector of permission_level_weights, (a permission_level is an account name plus a permission name) @@ -112,7 +108,7 @@ namespace eosiosystem { /** * Blockchain block header. - * + * * @details A block header is defined by: * - a timestamp, * - the producer that created it, @@ -140,7 +136,7 @@ namespace eosiosystem { /** * abi_hash - * + * * @details abi_hash is the structure underlying the abihash table and consists of: * - `owner`: the account owner of the contract's abi * - `hash`: is the sha256 hash of the abi/binary @@ -156,7 +152,7 @@ namespace eosiosystem { // Method parameters commented out to prevent generation of code that parses input data. /** * The EOSIO core native contract that governs authorization and contracts' abi. - * + * * @details */ class [[eosio::contract("eosio.system")]] native : public eosio::contract { @@ -166,15 +162,15 @@ namespace eosiosystem { /** * @{ - * These actions map one-on-one with the ones defined in + * 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, + * 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 - * + * New account action + * * @details Called after a new account is created. This code enforces resource-limits rules * for new accounts as well as new account naming conventions. * @@ -194,9 +190,9 @@ namespace eosiosystem { /** * Update authorization action. - * + * * @details Updates pemission for an account - * + * * @param account - the account for which the permission is updated * @param pemission - the permission name which is updated * @param parem - the parent of the permission which is updated @@ -210,9 +206,9 @@ namespace eosiosystem { /** * Delete authorization action. - * + * * @details Deletes the authorization for an account's permision. - * + * * @param account - the account for which the permission authorization is deleted, * @param permission - the permission name been deleted. */ @@ -222,16 +218,16 @@ namespace eosiosystem { /** * Link authorization action. - * - * @details Assigns a specific action from a contract to a permission you have created. Five system + * + * @details 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 - * is needed to pass authorization validation. If a link is set, that permission is used for authoraization + * 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 + * is needed to pass authorization validation. If a link is set, that permission is used for authoraization * validation otherwise then active is the default, with the exception of `eosio.any`. * `eosio.any` is an implicit permission which exists on every account; you can link actions to `eosio.any` - * and that will make it so linked actions are accessible to any permissions defined for the account. - * + * and that will make it so linked actions are accessible to any permissions defined for the account. + * * @param account - the permission's owner to be linked and the payer of the RAM needed to store this link, * @param code - the owner of the action to be linked, * @param type - the action to be linked, @@ -245,9 +241,9 @@ namespace eosiosystem { /** * Unlink authorization action. - * + * * @details 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, * @param type - the action to be unlinked. @@ -259,9 +255,9 @@ namespace eosiosystem { /** * Cancel delay action. - * + * * @details Cancels a deferred transaction. - * + * * @param canceling_auth - the permission that authorizes this action, * @param trx_id - the deferred transaction id to be cancelled. */ @@ -270,9 +266,9 @@ namespace eosiosystem { /** * On error action. - * + * * @details Called every time an error occurs while a transaction was processed. - * + * * @param sender_id - the id of the sender, * @param sent_trx - the transaction that failed. */ @@ -281,9 +277,9 @@ namespace eosiosystem { /** * Set abi action. - * + * * @details Sets the contract abi for an account. - * + * * @param account - the account for which to set the contract abi. * @param abi - the abi content to be set, in the form of a blob binary. */ @@ -292,9 +288,9 @@ namespace eosiosystem { /** * Set code action. - * + * * @details 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. * @param vmversion - reserved, set it to zero. diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 3fe90fad1..e2d07a59d 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #include #include @@ -135,7 +131,7 @@ namespace eosiosystem { const auto& market = _rammarket.get(ramcore_symbol.raw(), "ram market does not exist"); _rammarket.modify( market, same_payer, [&]( auto& es ) { - bytes_out = es.direct_convert( quant_after_fee, ram_symbol ).amount; + bytes_out = es.direct_convert( quant_after_fee, ram_symbol ).amount; }); check( bytes_out > 0, "must reserve a positive amount" ); @@ -208,7 +204,7 @@ namespace eosiosystem { get_resource_limits( res_itr->owner.value, &ram_bytes, &net, &cpu ); set_resource_limits( res_itr->owner.value, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); } - + { token::transfer_action transfer_act{ token_account, { {ram_account, active_permission}, {account, active_permission} } }; transfer_act.send( ram_account, account, asset(tokens_out), "sell ram" ); diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 06ebc5cce..125ae6579 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -1,7 +1,3 @@ -/** - * @copyright defined in eos/LICENSE.txt - */ - #include #include @@ -48,7 +44,7 @@ namespace eosiosystem { const asset delta_rex_stake = add_to_rex_balance( from, amount, rex_received ); runrex(2); update_rex_account( from, asset( 0, core_symbol() ), delta_rex_stake ); - // dummy action added so that amount of REX tokens purchased shows up in action trace + // dummy action added so that amount of REX tokens purchased shows up in action trace rex_results::buyresult_action buyrex_act( rex_account, std::vector{ } ); buyrex_act.send( rex_received ); } @@ -525,11 +521,11 @@ namespace eosiosystem { pool->total_unlent.amount, itr->payment.amount ); /// conditions for loan renewal - bool renew_loan = itr->payment <= itr->balance /// loan has sufficient balance - && itr->payment.amount < rented_tokens /// loan has favorable return + bool renew_loan = itr->payment <= itr->balance /// loan has sufficient balance + && itr->payment.amount < rented_tokens /// loan has favorable return && rex_loans_available(); /// no pending sell orders if ( renew_loan ) { - /// update rex_pool in order to account for renewed loan + /// update rex_pool in order to account for renewed loan add_loan_to_rex_pool( itr->payment, rented_tokens, false ); /// update renewed loan fields delta_stake = update_renewed_loan( idx, itr, rented_tokens ); @@ -1010,7 +1006,7 @@ namespace eosiosystem { * @brief Reads amount of REX in savings bucket and removes the bucket from maturities * * Reads and (temporarily) removes REX savings bucket from REX maturities in order to - * allow uniform processing of remaining buckets as savings is a special case. This + * allow uniform processing of remaining buckets as savings is a special case. This * function is used in conjunction with put_rex_savings. * * @param bitr - iterator pointing to rex_balance object @@ -1064,7 +1060,7 @@ namespace eosiosystem { current_vote_stake.amount = ( uint128_t(bitr->rex_balance.amount) * _rexpool.begin()->total_lendable.amount ) / _rexpool.begin()->total_rex.amount; _rexbalance.modify( bitr, same_payer, [&]( auto& rb ) { - rb.vote_stake.amount = current_vote_stake.amount; + rb.vote_stake.amount = current_vote_stake.amount; }); delta_stake = current_vote_stake.amount - init_vote_stake.amount; } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 31d1dc987..c5b89672c 100755 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #include #include diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index ee4c3e0bd..c20d64165 100755 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include @@ -20,10 +16,10 @@ namespace eosio { /** * @defgroup eosiotoken eosio.token * @ingroup eosiocontracts - * + * * eosio.token contract - * - * @details eosio.token contract defines the structures and actions that allow users to create, issue, and manage + * + * @details eosio.token contract defines the structures and actions that allow users to create, issue, and manage * tokens on eosio based blockchains. * @{ */ @@ -33,16 +29,16 @@ namespace eosio { /** * Create action. - * + * * @details Allows `issuer` account to create a token in supply of `maximum_supply`. * @param issuer - the account that creates the token, * @param maximum_supply - the maximum supply set for the token created. - * + * * @pre Token symbol has to be valid, * @pre Token symbol must not be already created, * @pre maximum_supply has to be smaller than the maximum supply allowed by the system: 1^62 - 1. - * @pre Maximum supply must be positive; - * + * @pre Maximum supply must be positive; + * * If validation is successful a new entry in statstable for token symbol scope gets created. */ [[eosio::action]] @@ -50,9 +46,9 @@ namespace eosio { const asset& maximum_supply); /** * Issue action. - * + * * @details This action issues to `to` account a `quantity` of tokens. - * + * * @param to - the account to issue tokens to, it must be the same as the issuer, * @param quntity - the amount of tokens to be issued, * @memo - the memo string that accompanies the token issue transaction. @@ -62,10 +58,10 @@ namespace eosio { /** * Retire action. - * - * @details The opposite for create action, if all validations succeed, + * + * @details The opposite for create action, if all validations succeed, * it debits the statstable.supply amount. - * + * * @param quantity - the quantity of tokens to retire, * @param memo - the memo string to accompany the transaction. */ @@ -74,10 +70,10 @@ namespace eosio { /** * Transfer action. - * + * * @details Allows `from` account to transfer to `to` account the `quantity` tokens. * One account is debited and the other is credited with quantity tokens. - * + * * @param from - the account to transfer from, * @param to - the account to be transferred to, * @param quantity - the quantity of tokens to be transferred, @@ -90,15 +86,15 @@ namespace eosio { const string& memo ); /** * Open action. - * - * @details Allows `ram_payer` to create an account `owner` with zero balance for + * + * @details Allows `ram_payer` to create an account `owner` with zero balance for * token `symbol` at the expense of `ram_payer`. - * + * * @param owner - the account to be created, * @param symbol - the token to be payed with by `ram_payer`, * @param ram_payer - the account that supports the cost of this action. - * - * More information can be read [here](https://github.com/EOSIO/eosio.contracts/issues/62) + * + * More information can be read [here](https://github.com/EOSIO/eosio.contracts/issues/62) * and [here](https://github.com/EOSIO/eosio.contracts/issues/61). */ [[eosio::action]] @@ -106,13 +102,13 @@ namespace eosio { /** * Close action. - * - * @details This action is the opposite for open, it closes the account `owner` + * + * @details This action is the opposite for open, it closes the account `owner` * for token `symbol`. - * + * * @param owner - the owner account to execute the close action for, * @param symbol - the symbol of the token to execute the close action for. - * + * * @pre The pair of owner plus symbol has to exist otherwise no action is executed, * @pre If the pair of owner plus symbol exists, the balance has to be zero. */ @@ -121,9 +117,9 @@ namespace eosio { /** * Get supply method. - * - * @details Gets the supply for token `sym_code`, created by `token_contract_account` account. - * + * + * @details Gets the supply for token `sym_code`, created by `token_contract_account` account. + * * @param token_contract_account - the account to get the supply for, * @param sym_code - the symbol to get the supply for. */ @@ -136,10 +132,10 @@ namespace eosio { /** * Get balance method. - * + * * @details Get the balance for a token `sym_code` created by `token_contract_account` account, * for account `owner`. - * + * * @param token_contract_account - the token creator account, * @param owner - the account for which the token balance is returned, * @param sym_code - the token for which the balance is returned. diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index fd294ac3b..9d246d4b6 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -1,8 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - #include namespace eosio { diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 657ce487c..05d9044ea 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include From b6fe0dae1626f98863bd8cd6ac8d43371d141a65 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 11 Jun 2019 10:54:31 -0400 Subject: [PATCH 007/106] RAM testing --- tests/eosio.system_tests.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index cd6bc62c0..c11b99c2b 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -17,10 +17,17 @@ struct _abi_hash { }; FC_REFLECT( _abi_hash, (owner)(hash) ); +struct connector { + asset balance; + double weight = .5; +}; +FC_REFLECT( connector, (balance)(weight) ); + using namespace eosio_system; BOOST_AUTO_TEST_SUITE(eosio_system_tests) + BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( "alice1111111" ) ); @@ -117,7 +124,34 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), sellram( "alice1111111", bought_bytes ) ); - BOOST_REQUIRE_EQUAL( core_sym::from_string("99396507.4158"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( false, get_row_by_account( config::system_account_name, config::system_account_name, + N(rammarket), symbol{SY(4,RAMCORE)}.value() ).empty() ); + + auto get_ram_market = [this]() -> fc::variant { + vector data = get_row_by_account( config::system_account_name, config::system_account_name, + N(rammarket), symbol{SY(4,RAMCORE)}.value() ); + BOOST_REQUIRE( !data.empty() ); + return abi_ser.binary_to_variant("exchange_state", data, abi_serializer_max_time); + }; + + transfer( "eosio", "alice1111111", core_sym::from_string("10000000.0000"), "eosio" ); + uint64_t bytes0 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); + + auto market = get_ram_market(); + const asset r0 = market["base"].as().balance; + const asset e0 = market["quote"].as().balance; + BOOST_REQUIRE_EQUAL( asset::from_string("0 RAM").get_symbol(), r0.get_symbol() ); + BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000").get_symbol(), e0.get_symbol() ); + + const asset payment = core_sym::from_string("10000000.0000"); + BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", payment ) ); + uint64_t bytes1 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); + + const int64_t fee = (payment.get_amount() + 199) / 200; + const double net_payment = payment.get_amount() - fee; + const int64_t expected_delta = net_payment * r0.get_amount() / ( net_payment + double(e0.get_amount()) ); + + BOOST_REQUIRE_EQUAL( expected_delta, bytes1 - bytes0 ); } FC_LOG_AND_RETHROW() From c0f351fc10ee55841eb1df15bc8e3998e8e34ad4 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 11 Jun 2019 17:24:14 -0400 Subject: [PATCH 008/106] More accurate input to buyram in buyrambytes --- .../include/eosio.system/exchange_state.hpp | 3 ++ .../eosio.system/src/delegate_bandwidth.cpp | 10 ++-- contracts/eosio.system/src/exchange_state.cpp | 15 ++++++ tests/eosio.system_tests.cpp | 49 +++++++++++++------ 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 94509c72b..c9836d202 100755 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -49,6 +49,9 @@ namespace eosiosystem { static int64_t get_bancor_output( int64_t inp_reserve, int64_t out_reserve, int64_t inp ); + static int64_t get_bancor_input( int64_t inp_reserve, + int64_t out_reserve, + int64_t out ); EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) ) }; diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index e2d07a59d..16ea90da9 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -83,12 +83,12 @@ namespace eosiosystem { * This action will buy an exact amount of ram and bill the payer the current market price. */ void system_contract::buyrambytes( const name& payer, const name& receiver, uint32_t bytes ) { - auto itr = _rammarket.find(ramcore_symbol.raw()); - auto tmp = *itr; - auto eosout = tmp.direct_convert( asset(bytes, ram_symbol), core_symbol() ); - - buyram( payer, receiver, eosout ); + const int64_t ram_reserve = itr->base.balance.amount; + const int64_t eos_reserve = itr->quote.balance.amount; + const int64_t cost = exchange_state::get_bancor_input( ram_reserve, eos_reserve, bytes ); + const int64_t cost_plus_fee = cost / double(0.995); + buyram( payer, receiver, asset{ cost_plus_fee, core_symbol() } ); } diff --git a/contracts/eosio.system/src/exchange_state.cpp b/contracts/eosio.system/src/exchange_state.cpp index 10fd11f8c..52a049576 100755 --- a/contracts/eosio.system/src/exchange_state.cpp +++ b/contracts/eosio.system/src/exchange_state.cpp @@ -87,4 +87,19 @@ namespace eosiosystem { return out; } + int64_t exchange_state::get_bancor_input( int64_t out_reserve, + int64_t inp_reserve, + int64_t out ) + { + const double ob = out_reserve; + const double ib = inp_reserve; + // const double ou = out; + + int64_t inp = (ib * out) / (ob - out); + + if ( inp < 0 ) inp = 0; + + return inp; + } + } /// namespace eosiosystem diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index c11b99c2b..0cd844bcf 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -30,6 +30,8 @@ BOOST_AUTO_TEST_SUITE(eosio_system_tests) BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { + auto within_one = [](int64_t a, int64_t b) -> bool { return std::abs( a - b ) <= 1; }; + BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( "alice1111111" ) ); transfer( "eosio", "alice1111111", core_sym::from_string("1000.0000"), "eosio" ); @@ -134,24 +136,41 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { return abi_ser.binary_to_variant("exchange_state", data, abi_serializer_max_time); }; - transfer( "eosio", "alice1111111", core_sym::from_string("10000000.0000"), "eosio" ); - uint64_t bytes0 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); + { + transfer( config::system_account_name, "alice1111111", core_sym::from_string("10000000.0000"), config::system_account_name ); + uint64_t bytes0 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); + + auto market = get_ram_market(); + const asset r0 = market["base"].as().balance; + const asset e0 = market["quote"].as().balance; + BOOST_REQUIRE_EQUAL( asset::from_string("0 RAM").get_symbol(), r0.get_symbol() ); + BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000").get_symbol(), e0.get_symbol() ); - auto market = get_ram_market(); - const asset r0 = market["base"].as().balance; - const asset e0 = market["quote"].as().balance; - BOOST_REQUIRE_EQUAL( asset::from_string("0 RAM").get_symbol(), r0.get_symbol() ); - BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000").get_symbol(), e0.get_symbol() ); + const asset payment = core_sym::from_string("10000000.0000"); + BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", payment ) ); + uint64_t bytes1 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); - const asset payment = core_sym::from_string("10000000.0000"); - BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", payment ) ); - uint64_t bytes1 = get_total_stake( "alice1111111" )["ram_bytes"].as_uint64(); + const int64_t fee = (payment.get_amount() + 199) / 200; + const double net_payment = payment.get_amount() - fee; + const int64_t expected_delta = net_payment * r0.get_amount() / ( net_payment + e0.get_amount() ); - const int64_t fee = (payment.get_amount() + 199) / 200; - const double net_payment = payment.get_amount() - fee; - const int64_t expected_delta = net_payment * r0.get_amount() / ( net_payment + double(e0.get_amount()) ); + BOOST_REQUIRE_EQUAL( expected_delta, bytes1 - bytes0 ); + } - BOOST_REQUIRE_EQUAL( expected_delta, bytes1 - bytes0 ); + { + transfer( config::system_account_name, "bob111111111", core_sym::from_string("100000.0000"), config::system_account_name ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("must reserve a positive amount"), + buyrambytes( "bob111111111", "bob111111111", 1 ) ); + + uint64_t bytes0 = get_total_stake( "bob111111111" )["ram_bytes"].as_uint64(); + BOOST_REQUIRE_EQUAL( success(), buyrambytes( "bob111111111", "bob111111111", 1024 ) ); + uint64_t bytes1 = get_total_stake( "bob111111111" )["ram_bytes"].as_uint64(); + BOOST_REQUIRE( within_one( 1024, bytes1 - bytes0 ) ); + + BOOST_REQUIRE_EQUAL( success(), buyrambytes( "bob111111111", "bob111111111", 1024 * 1024) ); + uint64_t bytes2 = get_total_stake( "bob111111111" )["ram_bytes"].as_uint64(); + BOOST_REQUIRE( within_one( 1024 * 1024, bytes2 - bytes1 ) ); + } } FC_LOG_AND_RETHROW() @@ -1563,7 +1582,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const int64_t expected_pervote_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ); const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; - const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); + const int64_t from_pervote_bucket = vote_shares[prod_index] * expected_pervote_bucket; BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); From c3883aa6f91ba232610df6e0d8ec78bca45720c1 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 12 Jun 2019 10:51:35 -0400 Subject: [PATCH 009/106] Small changes --- .../eosio.system/include/eosio.system/exchange_state.hpp | 4 ++-- contracts/eosio.system/src/exchange_state.cpp | 1 - tests/eosio.system_tests.cpp | 7 +------ 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index c9836d202..04119895a 100755 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -49,8 +49,8 @@ namespace eosiosystem { static int64_t get_bancor_output( int64_t inp_reserve, int64_t out_reserve, int64_t inp ); - static int64_t get_bancor_input( int64_t inp_reserve, - int64_t out_reserve, + static int64_t get_bancor_input( int64_t out_reserve, + int64_t inp_reserve, int64_t out ); EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) ) diff --git a/contracts/eosio.system/src/exchange_state.cpp b/contracts/eosio.system/src/exchange_state.cpp index 52a049576..48ad24a91 100755 --- a/contracts/eosio.system/src/exchange_state.cpp +++ b/contracts/eosio.system/src/exchange_state.cpp @@ -93,7 +93,6 @@ namespace eosiosystem { { const double ob = out_reserve; const double ib = inp_reserve; - // const double ou = out; int64_t inp = (ib * out) / (ob - out); diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 0cd844bcf..38528c2a6 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -27,11 +27,10 @@ using namespace eosio_system; BOOST_AUTO_TEST_SUITE(eosio_system_tests) +bool within_one(int64_t a, int64_t b) { return std::abs(a - b) <= 1; } BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { - auto within_one = [](int64_t a, int64_t b) -> bool { return std::abs( a - b ) <= 1; }; - BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( "alice1111111" ) ); transfer( "eosio", "alice1111111", core_sym::from_string("1000.0000"), "eosio" ); @@ -1434,8 +1433,6 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::t BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try { - auto within_one = [](int64_t a, int64_t b) -> bool { return std::abs( a - b ) <= 1; }; - const int64_t secs_per_year = 52 * 7 * 24 * 3600; const double usecs_per_year = secs_per_year * 1000000; const double cont_rate = 4.879/100.; @@ -3842,8 +3839,6 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_sell_rex, eosio_system_tester ) try { BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { - auto within_one = [](int64_t a, int64_t b) -> bool { return std::abs( a - b ) <= 1; }; - const asset init_balance = core_sym::from_string("3000000.0000"); const std::vector accounts = { N(aliceaccount), N(bobbyaccount), N(carolaccount), N(emilyaccount), N(frankaccount) }; account_name alice = accounts[0], bob = accounts[1], carol = accounts[2], emily = accounts[3], frank = accounts[4]; From a475e038b38c4b20c8dc65a80df037c509e333eb Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 20 Jun 2019 15:39:39 -0400 Subject: [PATCH 010/106] Implemented support for custom eosio and eosio.cdt installation paths. --- build.sh | 59 ++++++++++++++++++- scripts/.environment | 12 ++++ scripts/helper.sh | 135 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 2 deletions(-) create mode 100755 scripts/.environment create mode 100755 scripts/helper.sh diff --git a/build.sh b/build.sh index 001f3c64c..537451547 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,60 @@ -#! /bin/bash -set -e # exit on failure of any "simple" command (excludes &&, ||, or | chains) +#!/usr/bin/env bash +set -eo pipefail + +function usage() { + printf "Usage: $0 OPTION... + -e DIR Directory where EOSIO is installed. (Default: $HOME/eosio/X.Y) + -c DIR Directory where EOSIO.CDT is installed. (Default: /usr/local/eosio.cdt) + -y Noninteractive mode (Uses defaults for each prompt.) + -h Print this help menu. + \\n" "$0" 1>&2 + exit 1 +} + +if [ $# -ne 0 ]; then + while getopts "e:c:yh" opt; do + case "${opt}" in + e ) + EOSIO_DIR_PROMPT=$OPTARG + ;; + c ) + CDT_DIR_PROMPT=$OPTARG + ;; + y ) + NONINTERACTIVE=true + PROCEED=true + ;; + h ) + usage + ;; + ? ) + echo "Invalid Option!" 1>&2 + usage + ;; + : ) + echo "Invalid Option: -${OPTARG} requires an argument." 1>&2 + usage + ;; + * ) + usage + ;; + esac + done +fi + +# Source helper functions and variables. +. ./scripts/.environment +. ./scripts/helper.sh + +# Prompt user for location of eosio. +eosio-directory-prompt + +# Prompt user for location of eosio.cdt. +cdt-directory-prompt + +# Ensure eosio version is appropriate. +nodeos-version-check + printf "\t=========== Building eosio.contracts ===========\n\n" RED='\033[0;31m' NC='\033[0m' diff --git a/scripts/.environment b/scripts/.environment new file mode 100755 index 000000000..5f5b7731e --- /dev/null +++ b/scripts/.environment @@ -0,0 +1,12 @@ +export SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export REPO_ROOT="${SCRIPT_DIR}/.." +export TEST_DIR="${REPO_ROOT}/tests" + +export EOSIO_MIN_VERSION_MAJOR=$(cat $TEST_DIR/CMakeLists.txt | grep -E "^[[:blank:]]*set[[:blank:]]*\([[:blank:]]*EOSIO_VERSION_MIN" | tail -1 | sed 's/.*EOSIO_VERSION_MIN //g' | sed 's/ //g' | sed 's/"//g' | cut -d\) -f1 | cut -f1 -d '.') +export EOSIO_MIN_VERSION_MINOR=$(cat $TEST_DIR/CMakeLists.txt | grep -E "^[[:blank:]]*set[[:blank:]]*\([[:blank:]]*EOSIO_VERSION_MIN" | tail -1 | sed 's/.*EOSIO_VERSION_MIN //g' | sed 's/ //g' | sed 's/"//g' | cut -d\) -f1 | cut -f2 -d '.') +export EOSIO_SOFT_MAX_MAJOR=$(cat $TEST_DIR/CMakeLists.txt | grep -E "^[[:blank:]]*set[[:blank:]]*\([[:blank:]]*EOSIO_VERSION_SOFT_MAX" | tail -1 | sed 's/.*EOSIO_VERSION_SOFT_MAX //g' | sed 's/ //g' | sed 's/"//g' | cut -d\) -f1 | cut -f1 -d '.') +export EOSIO_SOFT_MAX_MINOR=$(cat $TEST_DIR/CMakeLists.txt | grep -E "^[[:blank:]]*set[[:blank:]]*\([[:blank:]]*EOSIO_VERSION_SOFT_MAX" | tail -1 | sed 's/.*EOSIO_VERSION_SOFT_MAX //g' | sed 's/ //g' | sed 's/"//g' | cut -d\) -f1 | cut -f2 -d '.') +export EOSIO_MAX_VERSION=$(cat $TEST_DIR/CMakeLists.txt | grep -E "^[[:blank:]]*set[[:blank:]]*\([[:blank:]]*EOSIO_VERSION_HARD_MAX" | tail -1 | sed 's/.*EOSIO_VERSION_HARD_MAX //g' | sed 's/ //g' | sed 's/"//g' | cut -d\) -f1) +export EOSIO_MAX_VERSION="${EOSIO_MAX_VERSION:-$(echo $EOSIO_SOFT_MAX_MAJOR.999)}" +export EOSIO_MAX_VERSION_MAJOR=$(echo $EOSIO_MAX_VERSION | cut -f1 -d '.') +export EOSIO_MAX_VERSION_MINOR=$(echo $EOSIO_MAX_VERSION | cut -f2 -d '.') \ No newline at end of file diff --git a/scripts/helper.sh b/scripts/helper.sh new file mode 100755 index 000000000..1ced68ed7 --- /dev/null +++ b/scripts/helper.sh @@ -0,0 +1,135 @@ +# Ensures passed in version values are supported. +function check-version-numbers() { + CHECK_VERSION_MAJOR=$1 + CHECK_VERSION_MINOR=$2 + + if [[ $CHECK_VERSION_MAJOR -lt $EOSIO_MIN_VERSION_MAJOR ]]; then + exit 1 + fi + if [[ $CHECK_VERSION_MAJOR -gt $EOSIO_MAX_VERSION_MAJOR ]]; then + exit 1 + fi + if [[ $CHECK_VERSION_MAJOR -eq $EOSIO_MIN_VERSION_MAJOR ]]; then + if [[ $CHECK_VERSION_MINOR -lt $EOSIO_MIN_VERSION_MINOR ]]; then + exit 1 + fi + fi + if [[ $CHECK_VERSION_MAJOR -eq $EOSIO_MAX_VERSION_MAJOR ]]; then + if [[ $CHECK_VERSION_MINOR -gt $EOSIO_MAX_VERSION_MINOR ]]; then + exit 1 + fi + fi + exit 0 +} + + +# Handles choosing which EOSIO directory to select when the default location is used. +function default-eosio-directories() { + REGEX='^[0-9]+([.][0-9]+)?$' + ALL_EOSIO_SUBDIRS=($(ls ${HOME}/eosio | sort -V)) + for ITEM in "${ALL_EOSIO_SUBDIRS[@]}"; do + if [[ "$ITEM" =~ $REGEX ]]; then + DIR_MAJOR=$(echo $ITEM | cut -f1 -d '.') + DIR_MINOR=$(echo $ITEM | cut -f2 -d '.') + if $(check-version-numbers $DIR_MAJOR $DIR_MINOR); then + PROMPT_EOSIO_DIRS+=($ITEM) + fi + fi + done + for ITEM in "${PROMPT_EOSIO_DIRS[@]}"; do + if [[ "$ITEM" =~ $REGEX ]]; then + EOSIO_VERSION=$ITEM + fi + done +} + + +# Prompts or sets default behavior for choosing EOSIO directory. +function eosio-directory-prompt() { + if [[ -z $EOSIO_DIR_PROMPT ]]; then + default-eosio-directories; + echo 'No EOSIO location was specified.' + while true; do + if [[ $NONINTERACTIVE != true ]]; then + if [[ -z $EOSIO_VERSION ]]; then + echo "No default EOSIO installations detected..." + PROCEED=n + else + printf "Is EOSIO installed in the default location: $HOME/eosio/$EOSIO_VERSION (y/n)" && read -p " " PROCEED + fi + fi + echo "" + case $PROCEED in + "" ) + echo "Is EOSIO installed in the default location?";; + 0 | true | [Yy]* ) + break;; + 1 | false | [Nn]* ) + if [[ $PROMPT_EOSIO_DIRS ]]; then + echo "Found these compatible EOSIO versions in the default location." + printf "$HOME/eosio/%s\n" "${PROMPT_EOSIO_DIRS[@]}" + fi + printf "Enter the installation location of EOSIO:" && read -e -p " " EOSIO_DIR_PROMPT; + break;; + * ) + echo "Please type 'y' for yes or 'n' for no.";; + esac + done + fi + export EOSIO_INSTALL_DIR="${EOSIO_DIR_PROMPT:-${HOME}/eosio/${EOSIO_VERSION}}" +} + + +# Prompts or default behavior for choosing EOSIO.CDT directory. +function cdt-directory-prompt() { + if [[ -z $CDT_DIR_PROMPT ]]; then + echo 'No EOSIO.CDT location was specified.' + while true; do + if [[ $NONINTERACTIVE != true ]]; then + printf "Is EOSIO.CDT installed in the default location? /usr/local/eosio.cdt (y/n)" && read -p " " PROCEED + fi + echo "" + case $PROCEED in + "" ) + echo "Is EOSIO.CDT installed in the default location?";; + 0 | true | [Yy]* ) + break;; + 1 | false | [Nn]* ) + printf "Enter the installation location of EOSIO.CDT:" && read -e -p " " CDT_DIR_PROMPT; + break;; + * ) + echo "Please type 'y' for yes or 'n' for no.";; + esac + done + fi + export CDT_INSTALL_DIR="${CDT_DIR_PROMPT:-/usr/local/eosio.cdt}" +} + + +# Ensures EOSIO is installed and compatible via version listed in tests/CMakeLists.txt. +function nodeos-version-check() { + INSTALLED_VERSION=$(echo $($EOSIO_INSTALL_DIR/bin/nodeos --version)) + INSTALLED_VERSION_MAJOR=$(echo $INSTALLED_VERSION | cut -f1 -d '.' | sed 's/v//g') + INSTALLED_VERSION_MINOR=$(echo $INSTALLED_VERSION | cut -f2 -d '.' | sed 's/v//g') + + if [[ -z $INSTALLED_VERSION_MAJOR || -z $INSTALLED_VERSION_MINOR ]]; then + echo "Could not determine EOSIO version. Exiting..." + exit 1; + fi + + if $(check-version-numbers $INSTALLED_VERSION_MAJOR $INSTALLED_VERSION_MINOR); then + if [[ $INSTALLED_VERSION_MAJOR -gt $EOSIO_SOFT_MAX_MAJOR ]]; then + echo "Detected EOSIO version is greater than recommended soft max: $EOSIO_SOFT_MAX_MAJOR.$EOSIO_SOFT_MAX_MINOR. Proceed with caution." + fi + if [[ $INSTALLED_VERSION_MAJOR -eq $EOSIO_SOFT_MAX_MAJOR && $INSTALLED_VERSION_MINOR -gt $EOSIO_SOFT_MAX_MINOR ]]; then + echo "Detected EOSIO version is greater than recommended soft max: $EOSIO_SOFT_MAX_MAJOR.$EOSIO_SOFT_MAX_MINOR. Proceed with caution." + fi + echo "Using EOSIO installation at: $EOSIO_INSTALL_DIR" + echo "Using EOSIO.CDT installation at: $CDT_INSTALL_DIR" + else + echo "Supported versions are: $EOSIO_MIN_VERSION_MAJOR.$EOSIO_MIN_VERSION_MINOR - $EOSIO_MAX_VERSION_MAJOR.$EOSIO_MAX_VERSION_MINOR" + echo "Invalid EOSIO installation. Exiting..." + exit 1; + fi + export CMAKE_FRAMEWORK_PATH="${EOSIO_INSTALL_DIR}:${CDT_INSTALL_DIR}:${CMAKE_PREFIX_PATH}" +} \ No newline at end of file From 31da03b15530cb25aa030f9fea6e688717201557 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 20 Jun 2019 15:58:16 -0400 Subject: [PATCH 011/106] Implemented support for custom eosio and eosio.cdt installation paths. --- docker/buildContracts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/buildContracts.sh b/docker/buildContracts.sh index 56f4e0de7..52e768a31 100755 --- a/docker/buildContracts.sh +++ b/docker/buildContracts.sh @@ -1,6 +1,6 @@ #!/bin/bash set -e # exit on failure of any "simple" command (excludes &&, ||, or | chains) cd /eosio.contracts -./build.sh +./build.sh -c /usr/opt/eosio.cdt -e /opt/eosio -y cd build tar -pczf /artifacts/contracts.tar.gz * From ba40c05ff5a0e2f3753107d54bfcdf9045c147ff Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 16:50:53 -0400 Subject: [PATCH 012/106] Fix wrong assertion in create_core_token (adapted from @elmato's commit d8b9e9666b33a6ca3e2dce3baec21afc410de3c6) --- tests/eosio.system_tester.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 0af1b9e02..21bf3ed88 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -52,7 +52,7 @@ class eosio_system_tester : public TESTER { } void create_core_token( symbol core_symbol = symbol{CORE_SYM} ) { - FC_ASSERT( core_symbol.precision() != 4, "create_core_token assumes precision of core token is 4" ); + FC_ASSERT( core_symbol.decimals() == 4, "create_core_token assumes core token has 4 digits of precision" ); create_currency( N(eosio.token), config::system_account_name, asset(100000000000000, core_symbol) ); issue(config::system_account_name, asset(10000000000000, core_symbol) ); BOOST_REQUIRE_EQUAL( asset(10000000000000, core_symbol), get_balance( "eosio", core_symbol ) ); @@ -413,7 +413,7 @@ class eosio_system_tester : public TESTER { return proceeds; } } - } + } return proceeds; } @@ -595,7 +595,7 @@ class eosio_system_tester : public TESTER { vector data = get_row_by_account( config::system_account_name, from, N(delband), receiver ); return data.empty() ? fc::variant() : abi_ser.binary_to_variant("delegated_bandwidth", data, abi_serializer_max_time); } - + asset get_rex_balance( const account_name& act ) const { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rexbal), act ); return data.empty() ? asset(0, symbol(SY(4, REX))) : abi_ser.binary_to_variant("rex_balance", data, abi_serializer_max_time)["rex_balance"].as(); From 165fbddf9d1fdf42f534610f680168e6ddbf26af Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 16:51:40 -0400 Subject: [PATCH 013/106] cleanup extraneous and inconsistent license references --- .../include/eosio.system/eosio.system.hpp | 8 ++------ .../include/eosio.system/native.hpp | 4 ---- .../eosio.system/src/delegate_bandwidth.cpp | 6 +----- contracts/eosio.system/src/rex.cpp | 18 +++++++----------- contracts/eosio.system/src/voting.cpp | 4 ---- .../include/eosio.token/eosio.token.hpp | 4 ---- contracts/eosio.token/src/eosio.token.cpp | 5 ----- tests/eosio.system_tester.hpp | 4 ---- 8 files changed, 10 insertions(+), 43 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 43b2c353c..5267ce555 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include @@ -481,10 +477,10 @@ namespace eosiosystem { */ [[eosio::action]] void mvtosavings( const name& owner, const asset& rex ); - + /** * Moves a specified amount of REX out of savings bucket. The moved amount - * will have the regular REX maturity period of 4 days. + * will have the regular REX maturity period of 4 days. */ [[eosio::action]] void mvfrsavings( const name& owner, const asset& rex ); diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index 868dea333..558af9b6f 100755 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 7f4270cf8..78a79e945 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #include #include @@ -134,7 +130,7 @@ namespace eosiosystem { ); channel_to_rex( ramfee_account, fee ); } - + int64_t bytes_out; const auto& market = _rammarket.get(ramcore_symbol.raw(), "ram market does not exist"); diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 6bb1c92a2..98e402a9a 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -1,7 +1,3 @@ -/** - * @copyright defined in eos/LICENSE.txt - */ - #include #include @@ -66,7 +62,7 @@ namespace eosiosystem { const asset delta_rex_stake = add_to_rex_balance( from, amount, rex_received ); runrex(2); update_rex_account( from, asset( 0, core_symbol() ), delta_rex_stake ); - // dummy action added so that amount of REX tokens purchased shows up in action trace + // dummy action added so that amount of REX tokens purchased shows up in action trace rex_results::buyresult_action buyrex_act( rex_account, std::vector{ } ); buyrex_act.send( rex_received ); } @@ -373,7 +369,7 @@ namespace eosiosystem { } /** - * @brief Moves a specified amount of REX to savings bucket + * @brief Moves a specified amount of REX to savings bucket * * @param owner - account name of REX owner * @param rex - amount of REX to be moved @@ -679,11 +675,11 @@ namespace eosiosystem { pool->total_unlent.amount, itr->payment.amount ); /// conditions for loan renewal - bool renew_loan = itr->payment <= itr->balance /// loan has sufficient balance - && itr->payment.amount < rented_tokens /// loan has favorable return + bool renew_loan = itr->payment <= itr->balance /// loan has sufficient balance + && itr->payment.amount < rented_tokens /// loan has favorable return && rex_loans_available(); /// no pending sell orders if ( renew_loan ) { - /// update rex_pool in order to account for renewed loan + /// update rex_pool in order to account for renewed loan add_loan_to_rex_pool( itr->payment, rented_tokens, false ); /// update renewed loan fields delta_stake = update_renewed_loan( idx, itr, rented_tokens ); @@ -1162,7 +1158,7 @@ namespace eosiosystem { * @brief Reads amount of REX in savings bucket and removes the bucket from maturities * * Reads and (temporarily) removes REX savings bucket from REX maturities in order to - * allow uniform processing of remaining buckets as savings is a special case. This + * allow uniform processing of remaining buckets as savings is a special case. This * function is used in conjunction with put_rex_savings. * * @param bitr - iterator pointing to rex_balance object @@ -1216,7 +1212,7 @@ namespace eosiosystem { current_vote_stake.amount = ( uint128_t(bitr->rex_balance.amount) * _rexpool.begin()->total_lendable.amount ) / _rexpool.begin()->total_rex.amount; _rexbalance.modify( bitr, same_payer, [&]( auto& rb ) { - rb.vote_stake.amount = current_vote_stake.amount; + rb.vote_stake.amount = current_vote_stake.amount; }); delta_stake = current_vote_stake.amount - init_vote_stake.amount; } diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 3d9016be4..5a49c07a9 100755 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #include #include diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index 2463d1212..b8c6a50db 100755 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index cd1e8bb4f..d75b8448a 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -1,8 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ - #include namespace eosio { diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 21bf3ed88..a153b582e 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -1,7 +1,3 @@ -/** - * @file - * @copyright defined in eos/LICENSE.txt - */ #pragma once #include From d741e40bf7640e68f483f91b65447ac48b89281f Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 16:52:30 -0400 Subject: [PATCH 014/106] fix links in README; set hard max for eosio dependency --- README.md | 11 ++++++----- tests/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 15c20659e..d20e4b7ca 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,16 @@ The design of the EOSIO blockchain calls for a number of smart contracts that ar 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.system](https://github.com/eosio/eosio.contracts/tree/master/eosio.system) - * [eosio.msig](https://github.com/eosio/eosio.contracts/tree/master/eosio.msig) - * [eosio.wrap](https://github.com/eosio/eosio.contracts/tree/master/eosio.wrap) + * [eosio.bios](./contracts/eosio.bios) + * [eosio.system](./contracts/eosio.system) + * [eosio.msig](./contracts/eosio.msig) + * [eosio.wrap](./contracts/eosio.wrap) The following unprivileged contract(s) are also part of the system. - * [eosio.token](https://github.com/eosio/eosio.contracts/tree/master/eosio.token) + * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio v1.7.x](https://github.com/EOSIO/eos/releases/tag/v1.7.0) +* [eosio v1.7.x](https://github.com/EOSIO/eos/releases/tag/v1.7.4) * [eosio.cdt v1.5.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.5.0) To build the contracts and the unit tests: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 40502b3f9..63aafa895 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required( VERSION 3.5 ) set(EOSIO_VERSION_MIN "1.6") set(EOSIO_VERSION_SOFT_MAX "1.7") -#set(EOSIO_VERSION_HARD_MAX "") +set(EOSIO_VERSION_HARD_MAX "1.7") find_package(eosio) From 271083e9dc1acdb17fac1367fdff2fa71934f855 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Thu, 20 Jun 2019 16:58:19 -0400 Subject: [PATCH 015/106] Code cleaning --- tests/eosio.system_tests.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 38528c2a6..be1e4e34c 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -1575,10 +1575,10 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - const int64_t expected_perblock_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ); - const int64_t expected_pervote_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ); + const int64_t expected_perblock_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year; + const int64_t expected_pervote_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year; - const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; + const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks; const int64_t from_pervote_bucket = vote_shares[prod_index] * expected_pervote_bucket; BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); @@ -1649,12 +1649,12 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - const int64_t expected_perblock_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) + const int64_t expected_perblock_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year + initial_perblock_bucket; - const int64_t expected_pervote_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ) + const int64_t expected_pervote_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year + initial_pervote_bucket; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks ; - const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); + const int64_t from_pervote_bucket = vote_shares[prod_index] * expected_pervote_bucket; BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); if (from_pervote_bucket >= 100 * 10000) { @@ -1786,10 +1786,10 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::uni const double votepay_share = initial_prod_info2["votepay_share"].as_double() + secs_between_prod_updates * prod_info["total_votes"].as_double(); const double tot_votepay_share = initial_tot_votepay_share + initial_tot_vpay_rate * secs_between_global_updates; - const int64_t expected_perblock_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) - + initial_perblock_bucket; - const int64_t expected_pervote_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ) - + initial_pervote_bucket; + const int64_t expected_perblock_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year + + initial_perblock_bucket; + const int64_t expected_pervote_bucket = initial_supply.get_amount() * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year + + initial_pervote_bucket; const int64_t from_perblock_bucket = initial_unpaid_blocks * expected_perblock_bucket / initial_tot_unpaid_blocks; const int64_t from_pervote_bucket = int64_t( ( votepay_share * expected_pervote_bucket ) / tot_votepay_share ); From eb1a2d3ff1bb36638840476cca1487e88c0997f1 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 7 Jun 2019 18:33:06 -0400 Subject: [PATCH 016/106] add Ricardian contracts --- README.md | 2 + contracts/CMakeLists.txt | 11 + contracts/eosio.bios/CMakeLists.txt | 4 + .../include/eosio.bios/eosio.bios.hpp | 17 - .../ricardian/eosio.bios.contracts.md.in | 183 +++++ contracts/eosio.bios/src/eosio.bios.cpp | 2 +- contracts/eosio.msig/CMakeLists.txt | 4 + .../ricardian/eosio.msig.contracts.md.in | 73 ++ contracts/eosio.system/CMakeLists.txt | 4 + .../ricardian/eosio.system.clauses.md | 63 ++ .../ricardian/eosio.system.contracts.md.in | 664 ++++++++++++++++++ contracts/eosio.token/CMakeLists.txt | 4 + .../ricardian/eosio.token.contracts.md.in | 95 +++ contracts/eosio.wrap/CMakeLists.txt | 4 + .../ricardian/eosio.wrap.contracts.md.in | 13 + contracts/icons/account.png | Bin 0 -> 3795 bytes contracts/icons/account.svg | 1 + contracts/icons/admin.png | Bin 0 -> 2937 bytes contracts/icons/admin.svg | 1 + contracts/icons/multisig.png | Bin 0 -> 1411 bytes contracts/icons/multisig.svg | 1 + contracts/icons/resource.png | Bin 0 -> 1913 bytes contracts/icons/resource.svg | 1 + contracts/icons/rex.png | Bin 0 -> 2770 bytes contracts/icons/rex.svg | 1 + contracts/icons/token.png | Bin 0 -> 4268 bytes contracts/icons/token.svg | 1 + contracts/icons/transfer.png | Bin 0 -> 3856 bytes contracts/icons/transfer.svg | 1 + contracts/icons/voting.png | Bin 0 -> 3238 bytes contracts/icons/voting.svg | 1 + 31 files changed, 1133 insertions(+), 18 deletions(-) create mode 100644 contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in create mode 100644 contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in create mode 100644 contracts/eosio.system/ricardian/eosio.system.clauses.md create mode 100644 contracts/eosio.system/ricardian/eosio.system.contracts.md.in create mode 100644 contracts/eosio.token/ricardian/eosio.token.contracts.md.in create mode 100644 contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in create mode 100644 contracts/icons/account.png create mode 100644 contracts/icons/account.svg create mode 100644 contracts/icons/admin.png create mode 100644 contracts/icons/admin.svg create mode 100644 contracts/icons/multisig.png create mode 100644 contracts/icons/multisig.svg create mode 100644 contracts/icons/resource.png create mode 100644 contracts/icons/resource.svg create mode 100644 contracts/icons/rex.png create mode 100644 contracts/icons/rex.svg create mode 100644 contracts/icons/token.png create mode 100644 contracts/icons/token.svg create mode 100644 contracts/icons/transfer.png create mode 100644 contracts/icons/transfer.svg create mode 100644 contracts/icons/voting.png create mode 100644 contracts/icons/voting.svg diff --git a/README.md b/README.md index dd7355441..bb6ecb1b1 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ After build: [MIT](./LICENSE) +The included icons are provided under the same terms as the software and accompanying documentation, the MIT License. We welcome contributions from the artistically-inclined members of the community, and if you do send us alternative icons, then you are providing them under those same terms. + ## Important See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties or merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index fb59ebf6e..69d438e14 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -5,6 +5,17 @@ project(contracts) set(EOSIO_WASM_OLD_BEHAVIOR "Off") find_package(eosio.cdt) +set(ICON_BASE_URL "http://127.0.0.1/ricardian_assets/eosio.contracts/icons") + +set(ACCOUNT_ICON_URI "account.png#3d55a2fc3a5c20b456f5657faf666bc25ffd06f4836c5e8256f741149b0b294f") +set(ADMIN_ICON_URI "admin.png#9bf1cec664863bd6aaac0f814b235f8799fb02c850e9aa5da34e8a004bd6518e") +set(MULTISIG_ICON_URI "multisig.png#4fb41d3cf02d0dd2d35a29308e93c2d826ec770d6bb520db668f530764be7153") +set(RESOURCE_ICON_URI "resource.png#3830f1ce8cb07f7757dbcf383b1ec1b11914ac34a1f9d8b065f07600fa9dac19") +set(REX_ICON_URI "rex.png#d229837fa62a464b9c71e06060aa86179adf0b3f4e3b8c4f9702f4f4b0c340a8") +set(TOKEN_ICON_URI "token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654") +set(TRANSFER_ICON_URI "transfer.png#5dfad0df72772ee1ccc155e670c1d124f5c5122f1d5027565df38b418042d1dd") +set(VOTING_ICON_URI "voting.png#db28cd3db6e62d4509af3644ce7d377329482a14bb4bfaca2aa5f1400d8e8a84") + add_subdirectory(eosio.bios) add_subdirectory(eosio.msig) add_subdirectory(eosio.system) diff --git a/contracts/eosio.bios/CMakeLists.txt b/contracts/eosio.bios/CMakeLists.txt index b8ce19a50..3709f70c1 100755 --- a/contracts/eosio.bios/CMakeLists.txt +++ b/contracts/eosio.bios/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.bios set_target_properties(eosio.bios PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.bios.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.bios.contracts.md @ONLY ) + +target_compile_options( eosio.bios PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 3bdb9148b..80e6faae9 100755 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -318,22 +318,6 @@ namespace eosio { set_resource_limits( account.value, ram_bytes, net_weight, cpu_weight ); } - /** - * Set global resource limits. - * - * @details Not implemented yet. - * Set global resource limits - * - * @param ram - ram limit - * @param net - net limit - * @param cpu - cpu limit - */ - [[eosio::action]] - void setglimits( uint64_t ram, uint64_t net, uint64_t cpu ) { - (void)ram; (void)net; (void)cpu; - require_auth( _self ); - } - /** * Set a new list of active producers, that is, a new producers' schedule. * @@ -460,7 +444,6 @@ namespace eosio { using setcode_action = action_wrapper<"setcode"_n, &bios::setcode>; using setpriv_action = action_wrapper<"setpriv"_n, &bios::setpriv>; using setalimits_action = action_wrapper<"setalimits"_n, &bios::setalimits>; - using setglimits_action = action_wrapper<"setglimits"_n, &bios::setglimits>; using setprods_action = action_wrapper<"setprods"_n, &bios::setprods>; using setparams_action = action_wrapper<"setparams"_n, &bios::setparams>; using reqauth_action = action_wrapper<"reqauth"_n, &bios::reqauth>; diff --git a/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in b/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in new file mode 100644 index 000000000..1acb02b6b --- /dev/null +++ b/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in @@ -0,0 +1,183 @@ +

activate

+ +--- +spec_version: "0.2.0" +title: Activate Protocol Feature +summary: 'Activate protocol feature {{nowrap feature_digest}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} activates the protocol feature with a digest of {{feature_digest}}. + +

canceldelay

+ +--- +spec_version: "0.2.0" +title: Cancel Delayed Transaction +summary: '{{nowrap canceling_auth.actor}} cancels a delayed transaction' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{canceling_auth.actor}} cancels the delayed transaction with id {{trx_id}}. + +

deleteauth

+ +--- +spec_version: "0.2.0" +title: Delete Account Permission +summary: 'Delete the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Delete the {{permission}} permission of {{account}}. + +

linkauth

+ +--- +spec_version: "0.2.0" +title: Link Action to Permission +summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}. + +{{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}} + +

newaccount

+ +--- +spec_version: "0.2.0" +title: Create New Account +summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{creator}} creates a new account with the name {{name}} and the following permissions: + +owner permission with authority: +{{to_json owner}} + +active permission with authority: +{{to_json active}} + +

reqactivated

+ +--- +spec_version: "0.2.0" +title: Assert Protocol Feature Activation +summary: 'Assert that protocol feature {{nowrap feature_digest}} has been activated' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +Assert that the protocol feature with a digest of {{feature_digest}} has been activated. + +

reqauth

+ +--- +spec_version: "0.2.0" +title: Assert Authorization +summary: 'Assert that authorization by {{nowrap from}} is provided' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Assert that authorization by {{from}} is provided. + +

setabi

+ +--- +spec_version: "0.2.0" +title: Deploy Contract ABI +summary: 'Deploy contract ABI on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy the ABI file associated with the contract on account {{account}}. + +

setalimits

+ +--- +spec_version: "0.2.0" +title: Adjust Resource Limits of Account +summary: 'Adjust resource limits of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} updates {{account}}’s resource limits to have a RAM quota of {{ram_bytes}} bytes, a NET bandwidth quota of {{net_weight}} and a CPU bandwidth quota of {{cpu_weight}}. + +

setcode

+ +--- +spec_version: "0.2.0" +title: Deploy Contract Code +summary: 'Deploy contract code on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy compiled contract code to the account {{account}}. + +

setparams

+ +--- +spec_version: "0.2.0" +title: Set System Parameters +summary: 'Set system parameters' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets system parameters to: +{{to_json params}} + +

setpriv

+ +--- +spec_version: "0.2.0" +title: Make an Account Privileged or Unprivileged +summary: '{{#if is_priv}}Make {{nowrap account}} privileged{{else}}Remove privileged status of {{nowrap account}}{{/if}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if is_priv}} +{{$action.account}} makes {{account}} privileged. +{{else}} +{{$action.account}} removes privileged status of {{account}}. +{{/if}} + +

setprods

+ +--- +spec_version: "0.2.0" +title: Set Block Producers +summary: 'Set block producer schedule' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} proposes a block producer schedule of: +{{#each schedule}} + 1. {{this.producer_name}} with a block signing key of {{this.block_signing_key}} +{{/each}} + +

unlinkauth

+ +--- +spec_version: "0.2.0" +title: Unlink Action from Permission +summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission. + +{{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}} + +

updateauth

+ +--- +spec_version: "0.2.0" +title: Modify Account Permission +summary: 'Add or update the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Modify, and create if necessary, the {{permission}} permission of {{account}} to have a parent permission of {{parent}} and the following authority: +{{to_json auth}} diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index fc8d2ff84..9a080e5e4 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -1,3 +1,3 @@ #include -EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(setparams)(reqauth)(setabi)(activate)(reqactivated) ) +EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setprods)(setparams)(reqauth)(setabi)(activate)(reqactivated) ) diff --git a/contracts/eosio.msig/CMakeLists.txt b/contracts/eosio.msig/CMakeLists.txt index 089587f28..0947ea9d0 100755 --- a/contracts/eosio.msig/CMakeLists.txt +++ b/contracts/eosio.msig/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.msig set_target_properties(eosio.msig PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.msig.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.msig.contracts.md @ONLY ) + +target_compile_options( eosio.msig PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in b/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in new file mode 100644 index 000000000..b9f3f35f8 --- /dev/null +++ b/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in @@ -0,0 +1,73 @@ +

approve

+ +--- +spec_version: "0.2.0" +title: Approve Proposed Transaction +summary: '{{nowrap level.actor}} approves the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{level.actor}} approves the {{proposal_name}} proposal proposed by {{proposer}} with the {{level.permission}} permission of {{level.actor}}. + +

cancel

+ +--- +spec_version: "0.2.0" +title: Cancel Proposed Transaction +summary: '{{nowrap canceler}} cancels the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{canceler}} cancels the {{proposal_name}} proposal submitted by {{proposer}}. + +

exec

+ +--- +spec_version: "0.2.0" +title: Execute Proposed Transaction +summary: '{{nowrap executer}} executes the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{executer}} executes the {{proposal_name}} proposal submitted by {{proposer}} if the minimum required approvals for the proposal have been secured. + +

invalidate

+ +--- +spec_version: "0.2.0" +title: Invalidate All Approvals +summary: '{{nowrap account}} invalidates approvals on outstanding proposals' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{account}} invalidates all approvals on proposals which have not yet executed. + +

propose

+ +--- +spec_version: "0.2.0" +title: Propose Transaction +summary: '{{nowrap proposer}} creates the {{nowrap proposal_name}}' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{proposer}} creates the {{proposal_name}} proposal for the following transaction: +{{to_json trx}} + +The proposal requests approvals from the following accounts at the specified permission levels: +{{#each requested}} + + {{this.permission}} permission of {{this.actor}} +{{/each}} + +If the proposed transaction is not executed prior to {{trx.expiration}}, the proposal will automatically expire. + +

unapprove

+ +--- +spec_version: "0.2.0" +title: Unapprove Proposed Transaction +summary: '{{nowrap level.actor}} revokes the approval previously provided to {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{level.actor}} revokes the approval previously provided at their {{level.permission}} permission level from the {{proposal_name}} proposal proposed by {{proposer}}. diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index de993ef05..e99eb37bd 100755 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -18,3 +18,7 @@ target_include_directories(rex.results set_target_properties(rex.results PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.rex") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.system.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.system.contracts.md @ONLY ) + +target_compile_options( eosio.system PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.system/ricardian/eosio.system.clauses.md b/contracts/eosio.system/ricardian/eosio.system.clauses.md new file mode 100644 index 000000000..19be74f81 --- /dev/null +++ b/contracts/eosio.system/ricardian/eosio.system.clauses.md @@ -0,0 +1,63 @@ +

UserAgreement

+ +User agreement for the chain can go here. + +

BlockProducerAgreement

+ +I, {{producer}}, hereby nominate myself for consideration as an elected block producer. + +If {{producer}} is selected to produce blocks by the system contract, I will sign blocks with {{producer_key}} and I hereby attest that I will keep this key secret and secure. + +If {{producer}} is unable to perform obligations under this contract I will resign my position by resubmitting this contract with the null producer key. + +I acknowledge that a block is 'objectively valid' if it conforms to the deterministic blockchain rules in force at the time of its creation, and is 'objectively invalid' if it fails to conform to those rules. + +{{producer}} hereby agrees to only use {{producer_key}} to sign messages under the following scenarios: + +* proposing an objectively valid block at the time appointed by the block scheduling algorithm; +* pre-confirming a block produced by another producer in the schedule when I find said block objectively valid; +* and, confirming a block for which {{producer}} has received pre-confirmation messages from more than two-thirds of the active block producers. + +I hereby accept liability for any and all provable damages that result from my: + +* signing two different block proposals with the same timestamp with {{producer_key}}; +* signing two different block proposals with the same block number with {{producer_key}}; +* signing any block proposal which builds off of an objectively invalid block; +* signing a pre-confirmation for an objectively invalid block; +* or, signing a confirmation for a block for which I do not possess pre-confirmation messages from more than two-thirds of the active block producers. + +I hereby agree that double-signing for a timestamp or block number in concert with two or more other block producers shall automatically be deemed malicious and cause {{producer}} to be subject to: + +* a fine equal to the past year of compensation received, +* immediate disqualification from being a producer, +* and/or other damages. + +An exception may be made if {{producer}} can demonstrate that the double-signing occurred due to a bug in the reference software; the burden of proof is on {{producer}}. + +I hereby agree not to interfere with the producer election process. I agree to process all producer election transactions that occur in blocks I create, to sign all objectively valid blocks I create that contain election transactions, and to sign all pre-confirmations and confirmations necessary to facilitate transfer of control to the next set of producers as determined by the system contract. + +I hereby acknowledge that more than two-thirds of the active block producers may vote to disqualify {{producer}} in the event {{producer}} is unable to produce blocks or is unable to be reached, according to criteria agreed to among block producers. + +If {{producer}} qualifies for and chooses to collect compensation due to votes received, {{producer}} will provide a public endpoint allowing at least 100 peers to maintain synchronization with the blockchain and/or submit transactions to be included. {{producer}} shall maintain at least one validating node with full state and signature checking and shall report any objectively invalid blocks produced by the active block producers. Reporting shall be via a method to be agreed to among block producers, said method and reports to be made public. + +The community agrees to allow {{producer}} to authenticate peers as necessary to prevent abuse and denial of service attacks; however, {{producer}} agrees not to discriminate against non-abusive peers. + +I agree to process transactions on a FIFO (first in, first out) best-effort basis and to honestly bill transactions for measured execution time. + +I {{producer}} agree not to manipulate the contents of blocks in order to derive profit from: the order in which transactions are included, or the hash of the block that is produced. + +I, {{producer}}, hereby agree to disclose and attest under penalty of perjury all ultimate beneficial owners of my business entity who own more than 10% and all direct shareholders. + +I, {{producer}}, hereby agree to cooperate with other block producers to carry out our respective and mutual obligations under this agreement, including but not limited to maintaining network stability and a valid blockchain. + +I, {{producer}}, agree to maintain a website hosted at {{url}} which contains up-to-date information on all disclosures required by this contract. + +I, {{producer}}, agree to set the location value of {{location}} such that {{producer}} is scheduled with minimal latency between my previous and next peer. + +I, {{producer}}, agree to maintain time synchronization within 10 ms of global atomic clock time, using a method agreed to among block producers. + +I, {{producer}}, agree not to produce blocks before my scheduled time unless I have received all blocks produced by the prior block producer. + +I, {{producer}}, agree not to publish blocks with timestamps more than 500ms in the future unless the prior block is more than 75% full by either NET or CPU bandwidth metrics. + +I, {{producer}}, agree not to set the RAM supply to more RAM than my nodes contain and to resign if I am unable to provide the RAM approved by more than two-thirds of active block producers, as shown in the system parameters. diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in new file mode 100644 index 000000000..2269428e9 --- /dev/null +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -0,0 +1,664 @@ +

activate

+ +--- +spec_version: "0.2.0" +title: Activate Protocol Feature +summary: 'Activate protocol feature {{nowrap feature_digest}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} activates the protocol feature with a digest of {{feature_digest}}. + +

bidname

+ +--- +spec_version: "0.2.0" +title: Bid On a Premium Account Name +summary: '{{nowrap bidder}} bids on the premium account name {{nowrap newname}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{bidder}} bids {{bid}} on an auction to own the premium account name {{newname}}. + +{{bidder}} transfers {{bid}} to the system to cover the cost of the bid, which will be returned to {{bidder}} only if {{bidder}} is later outbid in the auction for {{newname}} by another account. + +If the auction for {{newname}} closes with {{bidder}} remaining as the highest bidder, {{bidder}} will be authorized to create the account with name {{newname}}. + +## Bid refund behavior + +If {{bidder}}’s bid on {{newname}} is later outbid by another account, {{bidder}} will be able to claim back the transferred amount of {{bid}}. The system will attempt to automatically do this on behalf of {{bidder}}, but the automatic refund may occasionally fail which will then require {{bidder}} to manually claim the refund with the bidrefund action. + +## Auction close criteria + +The system should automatically close the auction for {{newname}} if it satisfies the condition that over a period of two minutes the following two properties continuously hold: + +- no one has bid on {{newname}} within the last 24 hours; +- and, the value of the latest bid on {{newname}} is greater than the value of the bids on each of the other open auctions. + +Be aware that the condition to close the auction described above are sufficient but not necessary. The auction for {{newname}} cannot close unless both of the properties are simultaneously satisfied, but it may be closed without requiring the properties to hold for a period of 2 minutes. + +

bidrefund

+ +--- +spec_version: "0.2.0" +title: Claim Refund on Name Bid +summary: 'Claim refund on {{nowrap newname}} bid' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{bidder}} claims refund on {{newname}} bid after being outbid by someone else. + +

buyram

+ +--- +spec_version: "0.2.0" +title: Buy RAM +summary: '{{nowrap payer}} buys RAM on behalf of {{nowrap receiver}} by paying {{nowrap quant}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{payer}} buys RAM on behalf of {{receiver}} by paying {{quant}}. This transaction will incur a 0.5% fee out of {{quant}} and the amount of RAM delivered will depend on market rates. + +

buyrambytes

+ +--- +spec_version: "0.2.0" +title: Buy RAM +summary: '{{nowrap payer}} buys {{nowrap bytes}} bytes of RAM on behalf of {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{payer}} buys approximately {{bytes}} bytes of RAM on behalf of {{receiver}} by paying market rates for RAM. This transaction will incur a 0.5% fee and the cost will depend on market rates. + +

buyrex

+ +--- +spec_version: "0.2.0" +title: Buy REX Tokens +summary: '{{nowrap from}} buys REX tokens in exchange for {{nowrap amount}} and his vote stake increases by {{nowrap amount}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{amount}} is taken out of {{from}}’s REX fund and used to purchase REX tokens at the current market exchange rate. In order for the action to succeed, {{from}} must have voted for a proxy or at least 21 block producers. {{amount}} is added to {{from}}’s vote stake. + +A sell order of the purchased amount can only be initiated after waiting for the maturity period of 4 to 5 days to pass. Even then, depending on the market conditions, the initiated sell order may not be executed immediately. + +

canceldelay

+ +--- +spec_version: "0.2.0" +title: Cancel Delayed Transaction +summary: '{{nowrap canceling_auth.actor}} cancels a delayed transaction' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{canceling_auth.actor}} cancels the delayed transaction with id {{trx_id}}. + +

claimrewards

+ +--- +spec_version: "0.2.0" +title: Claim Block Producer Rewards +summary: '{{nowrap owner}} claims block and vote rewards' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{owner}} claims block and vote rewards from the system. + +

closerex

+ +--- +spec_version: "0.2.0" +title: Cleanup Unused REX Data +summary: 'Delete REX related DB entries and free associated RAM' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Delete REX related DB entries and free associated RAM for {{owner}}. + +To fully delete all REX related DB entries, {{owner}} must ensure that their REX balance and REX fund amounts are both zero and they have no outstanding loans. + +

cnclrexorder

+ +--- +spec_version: "0.2.0" +title: Cancel Scheduled REX Sell Order +summary: '{{nowrap owner}} cancels a scheduled sell order if not yet filled' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} cancels their open sell order. + +

consolidate

+ +--- +spec_version: "0.2.0" +title: Consolidate REX Maturity Buckets Into One +summary: 'Consolidate REX maturity buckets into one' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Consolidate REX maturity buckets into one bucket that {{owner}} will not be able to sell until 4 to 5 days later. + +

defcpuloan

+ +--- +spec_version: "0.2.0" +title: Withdraw from the Fund of a Specific CPU Loan +summary: '{{nowrap from}} transfers {{nowrap amount}} from the fund of CPU loan number {{nowrap loan_num}} back to REX fund' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{amount}} from the fund of CPU loan number {{loan_num}} back to REX fund. + +

defnetloan

+ +--- +spec_version: "0.2.0" +title: Withdraw from the Fund of a Specific NET Loan +summary: '{{nowrap from}} transfers {{nowrap amount}} from the fund of NET loan number {{nowrap loan_num}} back to REX fund' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{amount}} from the fund of NET loan number {{loan_num}} back to REX fund. + +

delegatebw

+ +--- +spec_version: "0.2.0" +title: Stake Tokens for NET and/or CPU +summary: 'Stake tokens for NET and/or CPU and optionally transfer ownership' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{#if transfer}} {{from}} stakes on behalf of {{receiver}} {{stake_net_quantity}} for NET bandwidth and {{stake_cpu_quantity}} for CPU bandwidth. + +Staked tokens will also be transferred to {{receiver}}. The sum of these two quantities will be deducted from {{from}}’s liquid balance and add to the vote weight of {{receiver}}. +{{else}} +{{from}} stakes to self and delegates to {{receiver}} {{stake_net_quantity}} for NET bandwidth and {{stake_cpu_quantity}} for CPU bandwidth. + +The sum of these two quantities add to the vote weight of {{from}}. +{{/if}} + +

deleteauth

+ +--- +spec_version: "0.2.0" +title: Delete Account Permission +summary: 'Delete the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Delete the {{permission}} permission of {{account}}. + +

deposit

+ +--- +spec_version: "0.2.0" +title: Deposit Into REX Fund +summary: 'Add to {{nowrap owner}}’s REX fund by transferring {{nowrap amount}} from {{nowrap owner}}’s liquid balance' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Transfer {{amount}} from {{owner}}’s liquid balance to {{owner}}’s REX fund. All proceeds and expenses related to REX are added to or taken out of this fund. + +

fundcpuloan

+ +--- +spec_version: "0.2.0" +title: Deposit into the Fund of a Specific CPU Loan +summary: '{{nowrap from}} funds a CPU loan' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{payment}} from REX fund to the fund of CPU loan number {{loan_num}} in order to be used in loan renewal at expiry. {{from}} can withdraw the total balance of the loan fund at any time. + +

fundnetloan

+ +--- +spec_version: "0.2.0" +title: Deposit into the Fund of a Specific NET Loan +summary: '{{nowrap from}} funds a NET loan' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{payment}} from REX fund to the fund of NET loan number {{loan_num}} in order to be used in loan renewal at expiry. {{from}} can withdraw the total balance of the loan fund at any time. + +

init

+ +--- +spec_version: "0.2.0" +title: Initialize System Contract +summary: 'Initialize system contract' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +Initialize system contract. The core token symbol will be set to {{core}}. + +

linkauth

+ +--- +spec_version: "0.2.0" +title: Link Action to Permission +summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}. + +{{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}} + +

newaccount

+ +--- +spec_version: "0.2.0" +title: Create New Account +summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{creator}} creates a new account with the name {{name}} and the following permissions: + +owner permission with authority: +{{to_json owner}} + +active permission with authority: +{{to_json active}} + +

mvfrsavings

+ +--- +spec_version: "0.2.0" +title: Unlock REX Tokens +summary: '{{nowrap owner}} unlocks REX Tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} unlocks {{rex}} by moving it out of the REX savings bucket. The unlocked REX tokens cannot be sold until 4 to 5 days later. + +

mvtosavings

+ +--- +spec_version: "0.2.0" +title: Lock REX Tokens +summary: '{{nowrap owner}} locks REX Tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} locks {{rex}} by moving it into the REX savings bucket. The locked REX tokens cannot be sold directly and will have to be unlocked explicitly before selling. + +

refund

+ +--- +spec_version: "0.2.0" +title: Claim Unstaked Tokens +summary: 'Return previously unstaked tokens to {{nowrap owner}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Return previously unstaked tokens to {{owner}} after the unstaking period has elapsed. + +

regproducer

+ +--- +spec_version: "0.2.0" +title: Register as a Block Producer Candidate +summary: 'Register {{nowrap producer}} account as a block producer candidate' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +Register {{producer}} account as a block producer candidate. + +{{$clauses.BlockProducerAgreement}} + +

regproxy

+ +--- +spec_version: "0.2.0" +title: Register/unregister as a Proxy +summary: 'Register/unregister {{nowrap proxy}} as a proxy account' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{#if isproxy}} +{{proxy}} registers as a proxy that can vote on behalf of accounts that appoint it as their proxy. +{{else}} +{{proxy}} unregisters as a proxy that can vote on behalf of accounts that appoint it as their proxy. +{{/if}} + +

rentcpu

+ +--- +spec_version: "0.2.0" +title: Rent CPU Bandwidth for 30 Days +summary: '{{nowrap from}} pays {{nowrap loan_payment}} to rent CPU bandwidth for {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} pays {{loan_payment}} to rent CPU bandwidth on behalf of {{receiver}} for a period of 30 days. + +{{loan_payment}} is taken out of {{from}}’s REX fund. The market price determines the number of tokens to be staked to {{receiver}}’s CPU resources. In addition, {{from}} provides {{loan_fund}}, which is also taken out of {{from}}’s REX fund, to be used for automatic renewal of the loan. + +At expiration, if the loan has less funds than {{loan_payment}}, it is closed and lent tokens that have been staked are taken out of {{receiver}}’s CPU bandwidth. Otherwise, it is renewed at the market price at the time of renewal, that is, the number of staked tokens is recalculated and {{receiver}}’s CPU bandwidth is updated accordingly. {{from}} can fund or defund a loan at any time before expiration. When the loan is closed, {{from}} is refunded any tokens remaining in the loan fund. + +

rentnet

+ +--- +spec_version: "0.2.0" +title: Rent NET Bandwidth for 30 Days +summary: '{{nowrap from}} pays {{nowrap loan_payment}} to rent NET bandwidth for {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} pays {{loan_payment}} to rent NET bandwidth on behalf of {{receiver}} for a period of 30 days. + +{{loan_payment}} is taken out of {{from}}’s REX fund. The market price determines the number of tokens to be staked to {{receiver}}’s NET resources for 30 days. In addition, {{from}} provides {{loan_fund}}, which is also taken out of {{from}}’s REX fund, to be used for automatic renewal of the loan. + +At expiration, if the loan has less funds than {{loan_payment}}, it is closed and lent tokens that have been staked are taken out of {{receiver}}’s NET bandwidth. Otherwise, it is renewed at the market price at the time of renewal, that is, the number of staked tokens is recalculated and {{receiver}}’s NET bandwidth is updated accordingly. {{from}} can fund or defund a loan at any time before expiration. When the loan is closed, {{from}} is refunded any tokens remaining in the loan fund. + +

rexexec

+ +--- +spec_version: "0.2.0" +title: Perform REX Maintenance +summary: 'Process sell orders and expired loans' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Performs REX maintenance by processing a maximum of {{max}} REX sell orders and expired loans. Any account can execute this action. + +

rmvproducer

+ +--- +spec_version: "0.2.0" +title: Forcibly Unregister a Block Producer Candidate +summary: '{{nowrap producer}} is unregistered as a block producer candidate' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} unregisters {{producer}} as a block producer candidate. {{producer}} account will retain its votes and those votes can change based on voter stake changes or votes removed from {{producer}}. However new voters will not be able to vote for {{producer}} while it remains unregistered. + +

sellram

+ +--- +spec_version: "0.2.0" +title: Sell RAM From Account +summary: 'Sell unused RAM from {{nowrap account}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +Sell {{bytes}} bytes of unused RAM from account {{account}} at market price. This transaction will incur a 0.5% fee on the proceeds which depend on market rates. + +

sellrex

+ +--- +spec_version: "0.2.0" +title: Sell REX Tokens in Exchange for EOS +summary: '{{nowrap from}} sells {{nowrap rex}} tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} initiates a sell order to sell {{rex}} tokens at the market exchange rate during the time at which the order is ultimately executed. If {{from}} already has an open sell order in the sell queue, {{rex}} will be added to the amount of the sell order without change the position of the sell order within the queue. Once the sell order is executed, proceeds are added to {{from}}’s REX fund, the value of sold REX tokens is deducted from {{from}}’s vote stake, and votes are updated accordingly. + +Depending on the market conditions, it may not be possible to fill the entire sell order immediately. In such a case, the sell order is added to the back of a sell queue. A sell order at the front of the sell queue will automatically be executed when the market conditions allow for the entire order to be filled. Regardless of the market conditions, the system is designed to execute this sell order within 30 days. {{from}} can cancel the order at any time before it is filled using the cnclrexorder action. + +

setabi

+ +--- +spec_version: "0.2.0" +title: Deploy Contract ABI +summary: 'Deploy contract ABI on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy the ABI file associated with the contract on account {{account}}. + +

setacctcpu

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the CPU Quota of Account +summary: 'Explicitly manage the CPU bandwidth quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value cpu_weight}} +Explicitly manage the CPU bandwidth quota of account {{account}} by pinning it to a weight of {{cpu_weight}}. + +{{account}} can stake and unstake, however, it will not change their CPU bandwidth quota as long as it remains pinned. +{{else}} +Unpin the CPU bandwidth quota of account {{account}}. The CPU bandwidth quota of {{account}} will be driven by the current tokens staked for CPU bandwidth by {{account}}. +{{/if_has_value}} + +

setacctnet

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the NET Quota of Account +summary: 'Explicitly manage the NET bandwidth quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value net_weight}} +Explicitly manage the network bandwidth quota of account {{account}} by pinning it to a weight of {{net_weight}}. + +{{account}} can stake and unstake, however, it will not change their NET bandwidth quota as long as it remains pinned. +{{else}} +Unpin the NET bandwidth quota of account {{account}}. The NET bandwidth quota of {{account}} will be driven by the current tokens staked for NET bandwidth by {{account}}. +{{/if_has_value}} + +

setacctram

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the RAM Quota of Account +summary: 'Explicitly manage the RAM quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value ram_bytes}} +Explicitly manage the RAM quota of account {{account}} by pinning it to {{ram_bytes}} bytes. + +{{account}} can buy and sell RAM, however, it will not change their RAM quota as long as it remains pinned. +{{else}} +Unpin the RAM quota of account {{account}}. The RAM quota of {{account}} will be driven by the current RAM holdings of {{account}}. +{{/if_has_value}} + +

setalimits

+ +--- +spec_version: "0.2.0" +title: Adjust Resource Limits of Account +summary: 'Adjust resource limits of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} updates {{account}}’s resource limits to have a RAM quota of {{ram_bytes}} bytes, a NET bandwidth quota of {{net_weight}} and a CPU bandwidth quota of {{cpu_weight}}. + +

setcode

+ +--- +spec_version: "0.2.0" +title: Deploy Contract Code +summary: 'Deploy contract code on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy compiled contract code to the account {{account}}. + +

setparams

+ +--- +spec_version: "0.2.0" +title: Set System Parameters +summary: 'Set System Parameters' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets system parameters to: +{{to_json params}} + +

setpriv

+ +--- +spec_version: "0.2.0" +title: Make an Account Privileged or Unprivileged +summary: '{{#if is_priv}}Make {{nowrap account}} privileged{{else}}Remove privileged status of {{nowrap account}}{{/if}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if is_priv}} +{{$action.account}} makes {{account}} privileged. +{{else}} +{{$action.account}} removes privileged status of {{account}}. +{{/if}} + +

setram

+ +--- +spec_version: "0.2.0" +title: Configure the Available RAM +summary: 'Configure the available RAM' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} configures the available RAM to {{max_ram_size}} bytes. + +

setramrate

+ +--- +spec_version: "0.2.0" +title: Set the Rate of Increase of RAM +summary: 'Set the rate of increase of RAM per block' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets the rate of increase of RAM to {{bytes_per_block}} bytes/block. + +

setrex

+ +--- +spec_version: "0.2.0" +title: Adjust REX Pool Virtual Balance +summary: 'Adjust REX Pool Virtual Balance' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} adjusts REX loan rate by setting REX pool virtual balance to {{balance}}. No token transfer or issue is executed in this action. + +

undelegatebw

+ +--- +spec_version: "0.2.0" +title: Unstake Tokens for NET and/or CPU +summary: 'Unstake tokens for NET and/or CPU from {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{from}} unstakes from {{receiver}} {{unstake_net_quantity}} for NET bandwidth and {{unstake_cpu_quantity}} for CPU bandwidth. + +The sum of these two quantities will be removed from the vote weight of {{receiver}} and will be made available to {{from}} after an uninterrupted 3 day period without further unstaking by {{from}}. After the uninterrupted 3 day period passes, the system will attempt to automatically return the funds to {{from}}’s regular token balance. However, this automatic refund may occasionally fail which will then require {{from}} to manually claim the funds with the refund action. + +

unlinkauth

+ +--- +spec_version: "0.2.0" +title: Unlink Action from Permission +summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission. + +{{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}} + +

unregprod

+ +--- +spec_version: "0.2.0" +title: Unregister as a Block Producer Candidate +summary: '{{nowrap producer}} unregisters as a block producer candidate' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{producer}} unregisters as a block producer candidate. {{producer}} account will retain its votes and those votes can change based on voter stake changes or votes removed from {{producer}}. However new voters will not be able to vote for {{producer}} while it remains unregistered. + +

unstaketorex

+ +--- +spec_version: "0.2.0" +title: Buy REX Tokens Using Staked Tokens +summary: '{{nowrap owner}} buys REX tokens in exchange for tokens currently staked to NET and/or CPU' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from_net}} and {{from_cpu}} are withdrawn from {{receiver}}’s NET and CPU bandwidths respectively. These funds are used to purchase REX tokens at the current market exchange rate. In order for the action to succeed, {{owner}} must have voted for a proxy or at least 21 block producers. + +A sell order of the purchased amount can only be initiated after waiting for the maturity period of 4 to 5 days to pass. Even then, depending on the market conditions, the initiated sell order may not be executed immediately. + +

updateauth

+ +--- +spec_version: "0.2.0" +title: Modify Account Permission +summary: 'Add or update the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Modify, and create if necessary, the {{permission}} permission of {{account}} to have a parent permission of {{parent}} and the following authority: +{{to_json auth}} + +

updaterex

+ +--- +spec_version: "0.2.0" +title: Update REX Owner Vote Weight +summary: 'Update vote weight to current value of held REX tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Update vote weight of {{owner}} account to current value of held REX tokens. + +

updtrevision

+ +--- +spec_version: "0.2.0" +title: Update System Contract Revision Number +summary: 'Update system contract revision number' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} advances the system contract revision number to {{revision}}. + +

voteproducer

+ +--- +spec_version: "0.2.0" +title: Vote for Block Producers +summary: '{{nowrap voter}} votes for {{#if proxy}}the proxy {{nowrap proxy}}{{else}}up to 30 block producer candidates{{/if}}' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{#if proxy}} +{{voter}} votes for the proxy {{proxy}}. +At the time of voting the full weight of voter’s staked (CPU + NET) tokens will be cast towards each of the producers voted by {{proxy}}. +{{else}} +{{voter}} votes for the following block producer candidates: + +{{#each producers}} + + {{this}} +{{/each}} + +At the time of voting the full weight of voter’s staked (CPU + NET) tokens will be cast towards each of the above producers. +{{/if}} + +

withdraw

+ +--- +spec_version: "0.2.0" +title: Withdraw from REX Fund +summary: 'Withdraw {{nowrap amount}} from {{nowrap owner}}’s REX fund by transferring to {{owner}}’s liquid balance' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Withdraws {{amount}} from {{owner}}’s REX fund and transfer them to {{owner}}’s liquid balance. diff --git a/contracts/eosio.token/CMakeLists.txt b/contracts/eosio.token/CMakeLists.txt index 25c56b51e..cf53f62cd 100755 --- a/contracts/eosio.token/CMakeLists.txt +++ b/contracts/eosio.token/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.token set_target_properties(eosio.token PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.token.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.token.contracts.md @ONLY ) + +target_compile_options( eosio.token PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.token/ricardian/eosio.token.contracts.md.in b/contracts/eosio.token/ricardian/eosio.token.contracts.md.in new file mode 100644 index 000000000..f050eec77 --- /dev/null +++ b/contracts/eosio.token/ricardian/eosio.token.contracts.md.in @@ -0,0 +1,95 @@ +

close

+ +--- +spec_version: "0.2.0" +title: Close Token Balance +summary: 'Close {{nowrap owner}}’s zero quantity balance' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{owner}} agrees to close their zero quantity balance for the {{symbol_to_symbol_code symbol}} token. + +RAM will be refunded to the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. + +

create

+ +--- +spec_version: "0.2.0" +title: Create New Token +summary: 'Create a new token' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{$action.account}} agrees to create a new token with symbol {{asset_to_symbol_code maximum_supply}} to be managed by {{issuer}}. + +This action will not result any any tokens being issued into circulation. + +{{issuer}} will be allowed to issue tokens into circulation, up to a maximum supply of {{maximum_supply}}. + +RAM will deducted from {{$action.account}}’s resources to create the necessary records. + +

issue

+ +--- +spec_version: "0.2.0" +title: Issue Tokens into Circulation +summary: 'Issue {{nowrap quantity}} into circulation and transfer into {{nowrap to}}’s account' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +The token manager agrees to issue {{quantity}} into circulation, and transfer it into {{to}}’s account. + +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} + +If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, or the token manager does not have a balance for {{asset_to_symbol_code quantity}}, the token manager will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from the token manager’s resources to create the necessary records. + +This action does not allow the total quantity to exceed the max allowed supply of the token. + +

open

+ +--- +spec_version: "0.2.0" +title: Open Token Balance +summary: 'Open a zero quantity balance for {{nowrap owner}}' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{ram_payer}} agrees to establish a zero quantity balance for {{owner}} for the {{symbol_to_symbol_code symbol}} token. + +If {{owner}} does not have a balance for {{symbol_to_symbol_code symbol}}, {{ram_payer}} will be designated as the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. As a result, RAM will be deducted from {{ram_payer}}’s resources to create the necessary records. + +

retire

+ +--- +spec_version: "0.2.0" +title: Remove Tokens from Circulation +summary: 'Remove {{nowrap quantity}} from circulation' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +The token manager agrees to remove {{quantity}} from circulation, taken from their own account. + +{{#if memo}} There is a memo attached to the action stating: +{{memo}} +{{/if}} + +

transfer

+ +--- +spec_version: "0.2.0" +title: Transfer Tokens +summary: 'Send {{nowrap quantity}} from {{nowrap from}} to {{nowrap to}}' +icon: @ICON_BASE_URL@/@TRANSFER_ICON_URI@ +--- + +{{from}} agrees to send {{quantity}} to {{to}}. + +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} + +If {{from}} is not already the RAM payer of their {{asset_to_symbol_code quantity}} token balance, {{from}} will be designated as such. As a result, RAM will be deducted from {{from}}’s resources to refund the original RAM payer. + +If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, {{from}} will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from {{from}}’s resources to create the necessary records. diff --git a/contracts/eosio.wrap/CMakeLists.txt b/contracts/eosio.wrap/CMakeLists.txt index 6d064bff7..27d429194 100755 --- a/contracts/eosio.wrap/CMakeLists.txt +++ b/contracts/eosio.wrap/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.wrap set_target_properties(eosio.wrap PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.wrap.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.wrap.contracts.md @ONLY ) + +target_compile_options( eosio.wrap PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in b/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in new file mode 100644 index 000000000..8077a3472 --- /dev/null +++ b/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in @@ -0,0 +1,13 @@ +

exec

+ +--- +spec_version: "0.2.0" +title: Privileged Execute +summary: '{{nowrap executer}} executes a transaction while bypassing authority checks' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{executer}} executes the following transaction while bypassing authority checks: +{{to_json trx}} + +{{$action.account}} must also authorize this action. diff --git a/contracts/icons/account.png b/contracts/icons/account.png new file mode 100644 index 0000000000000000000000000000000000000000..7686587824ac663ffb79f3ee30d06821a26e6c26 GIT binary patch literal 3795 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 JPDHLkV1nnf{$~IH literal 0 HcmV?d00001 diff --git a/contracts/icons/account.svg b/contracts/icons/account.svg new file mode 100644 index 000000000..511f06499 --- /dev/null +++ b/contracts/icons/account.svg @@ -0,0 +1 @@ +Account \ No newline at end of file diff --git a/contracts/icons/admin.png b/contracts/icons/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..ae95364725ed2e9f6143044631d2ff136201fa2b GIT binary patch literal 2937 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 V=0Y3_AOE>PN6S$2rMg|je*nyqJZk^| literal 0 HcmV?d00001 diff --git a/contracts/icons/admin.svg b/contracts/icons/admin.svg new file mode 100644 index 000000000..fbc057179 --- /dev/null +++ b/contracts/icons/admin.svg @@ -0,0 +1 @@ +Admin \ No newline at end of file diff --git a/contracts/icons/multisig.png b/contracts/icons/multisig.png new file mode 100644 index 0000000000000000000000000000000000000000..00fa7564c88ea2785f53d641f150b32ec68a7b47 GIT binary patch literal 1411 zcmZ`%doqG{65Om;k{$VjOf%}jL|q`{EKZ_{CyDS4zk z(jazeJThn}$`&WHgx7r|KPRBU)0;w2-ok=^j-Q{e~v!@bbksTMV)7UQT}8uv~^<) zI$fbW_lQS}W+oVL*;zwR1mJXycr06F{D&lRfmxK^r3bp`3GuFvkN6LW)?nAOQ93fq z{NKv|vE^}24I13&Wh`o#ToS$=*UB6&S+wz!O>_dYbMCipI)V7ntxsjw*ty)zAVSf@ z&_Dim2n9$=tBf-Io~;tQ+n($H@(}~A^u%D4Pc8_u^V;B0OaS5lReOLObZmOx;;G}#;8*|+;c2be4I3`gN zhA*dU-77eHcf@h4FR%G z^aZ0lMorCFr^CEtC{Ygw9Xv9H7uht5$`Kn7A&0(ix?>tq_wz@c;Czv+$H0B<@fC5_ z9^O&Zp-ZogJ!__ydf~*kd1zwdI~!h10hy_Vp5G`5#au9wFm3rbh33#LfS1xF(Rp3d zJI;SCx#J!;ZMoY>*CG>nzF~t|Qfl^Un0IA!!>OAI5=x`k}(g&Oz9Nt*cBh=0VG`vkBgj_>ji16&N=NetoxA@plV?sUDV0z&_Nds zzHBn;p*55~yBEcF0$Ep$~xv06jiA|H79p$LBE)8|Qx+v=u(O)N^t zRtH#rkk{syuG>An9-Go<{SB_$5xc_H^jz1y*RJg1-A7NY4@lW*x7xn&+;8m~?QvN>T-E3}C(Y{}`$>K-Ikm~!K&AM#mwr|S`X<*0X7g}z{(qH(X( z31&CWc{@Zxd}+R_Q0^=S3M|f29sr(*nyMR5^)AyiJZyIQWmk5p1~sg^zjorepylGp zgj$P1Xqrvaelf)=g)FDMUFW5j)@VI^UT~$UKB*WO%k%fCyfRP-|G?X8V*)#&nfEj6 YBtQ`z6CivXCH{CNh3rMDa-pC88^Gy0WB>pF literal 0 HcmV?d00001 diff --git a/contracts/icons/multisig.svg b/contracts/icons/multisig.svg new file mode 100644 index 000000000..d9167fb2c --- /dev/null +++ b/contracts/icons/multisig.svg @@ -0,0 +1 @@ +Multi Sig \ No newline at end of file diff --git a/contracts/icons/resource.png b/contracts/icons/resource.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1bd127de7b7adb74c5d5765db70a036fd0aa8f GIT binary patch literal 1913 zcmZ`)X;72r7Jk3v3rUbAhzdcFutg}ftU*A)ghh$S9s{zJkjPRZ5D~&=hYv_)5n2{6 z?uyE-vKAEx2$cwEr6L6t1QZDr1=%H(2(sKvXYSnktNTnXHn@iK#cQN17U1Bia1wiuy-wzn?2E zO-ntqxw)ymt=dhtt`hI#;VVnOFkn!9fenCME8UsKNE(_M9=v~(qySh)w|l>qrVZJg zWJY=qo{cPeD#^dHs%8Ln%;nhGqDbIxAel~zjS$&rI~(y%4F0VbW!k&0TgYU^kI^7QI zo*6`4>LJIf#+h74bp(8*sJsY1!NVw#taO-eetMQ@tT+L-otSu);kn-hVIP10>p&D- z3f(ul5tG}Q_^k1w;Sgj_HPvB`hA@^T9_6g|-^@hd`i`iKiI3SI`ntBxSRW99d3O=q zP5Y*IHc25^-aZHs&RbzU_E+!a%=;B!6cz$hjRN~GWCf%jDS&qU;SLoZ8BL{^S$aMJ zvG_a2q=_yQ)9i6ctQ@I7HuI;9O=%r|ui>TGwPKO6hz4YLz4g#>Mbg>nB%;Krc;k zR%ztmV@_fbb&zA*#|GXLy9WX(st#$xl9iKl-;X;oRU=Wg!l=im;~e%!TV7u)2*HSA zQSEcc+%3+V}|AVxANkq;~ra21-~uijQef``8a|4 z&-&>(->x)nJ4`Nvz8<3-<7@ax=_uSgo-XnV9yzzx$BAQd2|&#x=RFpP%){dFU4g z11agtk9rcj@~uLuaHTHZXKVOT%3c;JGhib60d6~$g|)86Bbc56s5^jyR-C4nn8R{BxO?@e^c|@teZ#tpFnYf3RS&Rs##B z%BcGvOhC!--W#CfiktR-Pu<@K&lU2b6nVw2ED@3mPG;xqYtw{874!0{fhjgw&M^!U zj%EKc(i?r){I2GM-J;jr%Y{%&>tmvt=)AdZyc2S#U6Ez`1{~7EinU@8T0d-9ZGU%D zSUt-X8aJs$H=l|QrIbPobD(7Q7nS=&`YmVoJcrNkYaiBSJ4N+EnJG78OmCF zZzz@pBbvzmLMdv80n$wSGfzd7Z0|j}&X8gk__t4`IjLr_pJ*%1xf7|&sZRZ1eAKgfsSDGj%m`;!J#Cf65piZ5<5Rj8_2@Y8)GI^_-~#s_AB12g`?0(nO|i|= z6Ud<^(@2>m-riQ(?mte8aom~M;W`cD5rF##;vmb`SZ9cY|AMnmyAqUY7IRlA zQBl*e^=#?A5N5W3!wvOd3raS|O&oszyqWP%t4 lQzThj4saQu7QLp*0xy<3x9!Ue2$20bKzH$Qu5n~#{0CM4EzSS{ literal 0 HcmV?d00001 diff --git a/contracts/icons/resource.svg b/contracts/icons/resource.svg new file mode 100644 index 000000000..4a4755928 --- /dev/null +++ b/contracts/icons/resource.svg @@ -0,0 +1 @@ +Resource \ No newline at end of file diff --git a/contracts/icons/rex.png b/contracts/icons/rex.png new file mode 100644 index 0000000000000000000000000000000000000000..b43ee27fcf6180649c35b0739a74e37bc34d08ea GIT binary patch literal 2770 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 literal 0 HcmV?d00001 diff --git a/contracts/icons/rex.svg b/contracts/icons/rex.svg new file mode 100644 index 000000000..99f77f373 --- /dev/null +++ b/contracts/icons/rex.svg @@ -0,0 +1 @@ +Rex \ No newline at end of file diff --git a/contracts/icons/token.png b/contracts/icons/token.png new file mode 100644 index 0000000000000000000000000000000000000000..445188a0247749231e2de8832ac651a32a9a6c88 GIT binary patch literal 4268 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 literal 0 HcmV?d00001 diff --git a/contracts/icons/token.svg b/contracts/icons/token.svg new file mode 100644 index 000000000..67ff415ba --- /dev/null +++ b/contracts/icons/token.svg @@ -0,0 +1 @@ +Token_1 \ No newline at end of file diff --git a/contracts/icons/transfer.png b/contracts/icons/transfer.png new file mode 100644 index 0000000000000000000000000000000000000000..d9c021957516ff0e1873a54feb4f40f547c62bed GIT binary patch literal 3856 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 C9O3i; literal 0 HcmV?d00001 diff --git a/contracts/icons/transfer.svg b/contracts/icons/transfer.svg new file mode 100644 index 000000000..06da6325c --- /dev/null +++ b/contracts/icons/transfer.svg @@ -0,0 +1 @@ +Transfer_1 \ No newline at end of file diff --git a/contracts/icons/voting.png b/contracts/icons/voting.png new file mode 100644 index 0000000000000000000000000000000000000000..0356bddaf2b0f61f82f8dbd7cfad977e0757b187 GIT binary patch literal 3238 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 Z0VhTSOesfxtUm={pRKdagFTE({{svY!SDb8 literal 0 HcmV?d00001 diff --git a/contracts/icons/voting.svg b/contracts/icons/voting.svg new file mode 100644 index 000000000..fac870898 --- /dev/null +++ b/contracts/icons/voting.svg @@ -0,0 +1 @@ +Voting_1 \ No newline at end of file From 721b448ac089586ae844cd589f619dc64e1e0043 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 18:06:44 -0400 Subject: [PATCH 017/106] update README links --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bb6ecb1b1..c610475dd 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,16 @@ The design of the EOSIO blockchain calls for a number of smart contracts that ar 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](https://github.com/EOSIO/eosio.contracts/tree/master/contracts/eosio.bios) - * [eosio.system](https://github.com/EOSIO/eosio.contracts/tree/master/contracts/eosio.system) - * [eosio.msig](https://github.com/EOSIO/eosio.contracts/tree/master/contracts/eosio.msig) - * [eosio.wrap](https://github.com/EOSIO/eosio.contracts/tree/master/contracts/eosio.wrap) + * [eosio.bios](./contracts/eosio.bios) + * [eosio.system](./contracts/eosio.system) + * [eosio.msig](./contracts/eosio.msig) + * [eosio.wrap](./contracts/eosio.wrap) The following unprivileged contract(s) are also part of the system. - * [eosio.token](https://github.com/EOSIO/eosio.contracts/tree/master/contracts/eosio.token) + * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.0-rc1) +* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.0-rc2) * [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.1) To build the contracts and the unit tests: From 1d53ec4261d45e987cda49513161b5d432183e6b Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 7 Jun 2019 18:33:06 -0400 Subject: [PATCH 018/106] add Ricardian contracts --- README.md | 2 + contracts/CMakeLists.txt | 11 + contracts/eosio.bios/CMakeLists.txt | 4 + .../include/eosio.bios/eosio.bios.hpp | 9 +- .../ricardian/eosio.bios.contracts.md.in | 161 +++++ contracts/eosio.bios/src/eosio.bios.cpp | 2 +- contracts/eosio.msig/CMakeLists.txt | 4 + .../ricardian/eosio.msig.contracts.md.in | 73 ++ contracts/eosio.system/CMakeLists.txt | 4 + .../ricardian/eosio.system.clauses.md | 63 ++ .../ricardian/eosio.system.contracts.md.in | 653 ++++++++++++++++++ contracts/eosio.token/CMakeLists.txt | 4 + .../ricardian/eosio.token.contracts.md.in | 95 +++ contracts/eosio.wrap/CMakeLists.txt | 4 + .../ricardian/eosio.wrap.contracts.md.in | 13 + contracts/icons/account.png | Bin 0 -> 3795 bytes contracts/icons/account.svg | 1 + contracts/icons/admin.png | Bin 0 -> 2937 bytes contracts/icons/admin.svg | 1 + contracts/icons/multisig.png | Bin 0 -> 1411 bytes contracts/icons/multisig.svg | 1 + contracts/icons/resource.png | Bin 0 -> 1913 bytes contracts/icons/resource.svg | 1 + contracts/icons/rex.png | Bin 0 -> 2770 bytes contracts/icons/rex.svg | 1 + contracts/icons/token.png | Bin 0 -> 4268 bytes contracts/icons/token.svg | 1 + contracts/icons/transfer.png | Bin 0 -> 3856 bytes contracts/icons/transfer.svg | 1 + contracts/icons/voting.png | Bin 0 -> 3238 bytes contracts/icons/voting.svg | 1 + 31 files changed, 1101 insertions(+), 9 deletions(-) create mode 100644 contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in create mode 100644 contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in create mode 100644 contracts/eosio.system/ricardian/eosio.system.clauses.md create mode 100644 contracts/eosio.system/ricardian/eosio.system.contracts.md.in create mode 100644 contracts/eosio.token/ricardian/eosio.token.contracts.md.in create mode 100644 contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in create mode 100644 contracts/icons/account.png create mode 100644 contracts/icons/account.svg create mode 100644 contracts/icons/admin.png create mode 100644 contracts/icons/admin.svg create mode 100644 contracts/icons/multisig.png create mode 100644 contracts/icons/multisig.svg create mode 100644 contracts/icons/resource.png create mode 100644 contracts/icons/resource.svg create mode 100644 contracts/icons/rex.png create mode 100644 contracts/icons/rex.svg create mode 100644 contracts/icons/token.png create mode 100644 contracts/icons/token.svg create mode 100644 contracts/icons/transfer.png create mode 100644 contracts/icons/transfer.svg create mode 100644 contracts/icons/voting.png create mode 100644 contracts/icons/voting.svg diff --git a/README.md b/README.md index d20e4b7ca..7cae0fcac 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ After build: [MIT](./LICENSE) +The included icons are provided under the same terms as the software and accompanying documentation, the MIT License. We welcome contributions from the artistically-inclined members of the community, and if you do send us alternative icons, then you are providing them under those same terms. + ## Important See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties or merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index fb59ebf6e..69d438e14 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -5,6 +5,17 @@ project(contracts) set(EOSIO_WASM_OLD_BEHAVIOR "Off") find_package(eosio.cdt) +set(ICON_BASE_URL "http://127.0.0.1/ricardian_assets/eosio.contracts/icons") + +set(ACCOUNT_ICON_URI "account.png#3d55a2fc3a5c20b456f5657faf666bc25ffd06f4836c5e8256f741149b0b294f") +set(ADMIN_ICON_URI "admin.png#9bf1cec664863bd6aaac0f814b235f8799fb02c850e9aa5da34e8a004bd6518e") +set(MULTISIG_ICON_URI "multisig.png#4fb41d3cf02d0dd2d35a29308e93c2d826ec770d6bb520db668f530764be7153") +set(RESOURCE_ICON_URI "resource.png#3830f1ce8cb07f7757dbcf383b1ec1b11914ac34a1f9d8b065f07600fa9dac19") +set(REX_ICON_URI "rex.png#d229837fa62a464b9c71e06060aa86179adf0b3f4e3b8c4f9702f4f4b0c340a8") +set(TOKEN_ICON_URI "token.png#207ff68b0406eaa56618b08bda81d6a0954543f36adc328ab3065f31a5c5d654") +set(TRANSFER_ICON_URI "transfer.png#5dfad0df72772ee1ccc155e670c1d124f5c5122f1d5027565df38b418042d1dd") +set(VOTING_ICON_URI "voting.png#db28cd3db6e62d4509af3644ce7d377329482a14bb4bfaca2aa5f1400d8e8a84") + add_subdirectory(eosio.bios) add_subdirectory(eosio.msig) add_subdirectory(eosio.system) diff --git a/contracts/eosio.bios/CMakeLists.txt b/contracts/eosio.bios/CMakeLists.txt index b8ce19a50..3709f70c1 100755 --- a/contracts/eosio.bios/CMakeLists.txt +++ b/contracts/eosio.bios/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.bios set_target_properties(eosio.bios PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.bios.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.bios.contracts.md @ONLY ) + +target_compile_options( eosio.bios PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index e3acabe76..4a59591f5 100755 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -111,12 +111,6 @@ namespace eosio { set_resource_limits( account.value, ram_bytes, net_weight, cpu_weight ); } - [[eosio::action]] - void setglimits( uint64_t ram, uint64_t net, uint64_t cpu ) { - (void)ram; (void)net; (void)cpu; - require_auth( _self ); - } - [[eosio::action]] void setprods( std::vector schedule ) { (void)schedule; // schedule argument just forces the deserialization of the action data into vector (necessary check) @@ -165,7 +159,7 @@ namespace eosio { }; typedef eosio::multi_index< "abihash"_n, abi_hash > abi_hash_table; - + using newaccount_action = action_wrapper<"newaccount"_n, &bios::newaccount>; using updateauth_action = action_wrapper<"updateauth"_n, &bios::updateauth>; using deleteauth_action = action_wrapper<"deleteauth"_n, &bios::deleteauth>; @@ -175,7 +169,6 @@ namespace eosio { using setcode_action = action_wrapper<"setcode"_n, &bios::setcode>; using setpriv_action = action_wrapper<"setpriv"_n, &bios::setpriv>; using setalimits_action = action_wrapper<"setalimits"_n, &bios::setalimits>; - using setglimits_action = action_wrapper<"setglimits"_n, &bios::setglimits>; using setprods_action = action_wrapper<"setprods"_n, &bios::setprods>; using setparams_action = action_wrapper<"setparams"_n, &bios::setparams>; using reqauth_action = action_wrapper<"reqauth"_n, &bios::reqauth>; diff --git a/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in b/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in new file mode 100644 index 000000000..725ad6320 --- /dev/null +++ b/contracts/eosio.bios/ricardian/eosio.bios.contracts.md.in @@ -0,0 +1,161 @@ +

canceldelay

+ +--- +spec_version: "0.2.0" +title: Cancel Delayed Transaction +summary: '{{nowrap canceling_auth.actor}} cancels a delayed transaction' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{canceling_auth.actor}} cancels the delayed transaction with id {{trx_id}}. + +

deleteauth

+ +--- +spec_version: "0.2.0" +title: Delete Account Permission +summary: 'Delete the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Delete the {{permission}} permission of {{account}}. + +

linkauth

+ +--- +spec_version: "0.2.0" +title: Link Action to Permission +summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}. + +{{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}} + +

newaccount

+ +--- +spec_version: "0.2.0" +title: Create New Account +summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{creator}} creates a new account with the name {{name}} and the following permissions: + +owner permission with authority: +{{to_json owner}} + +active permission with authority: +{{to_json active}} + +

reqauth

+ +--- +spec_version: "0.2.0" +title: Assert Authorization +summary: 'Assert that authorization by {{nowrap from}} is provided' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Assert that authorization by {{from}} is provided. + +

setabi

+ +--- +spec_version: "0.2.0" +title: Deploy Contract ABI +summary: 'Deploy contract ABI on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy the ABI file associated with the contract on account {{account}}. + +

setalimits

+ +--- +spec_version: "0.2.0" +title: Adjust Resource Limits of Account +summary: 'Adjust resource limits of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} updates {{account}}’s resource limits to have a RAM quota of {{ram_bytes}} bytes, a NET bandwidth quota of {{net_weight}} and a CPU bandwidth quota of {{cpu_weight}}. + +

setcode

+ +--- +spec_version: "0.2.0" +title: Deploy Contract Code +summary: 'Deploy contract code on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy compiled contract code to the account {{account}}. + +

setparams

+ +--- +spec_version: "0.2.0" +title: Set System Parameters +summary: 'Set system parameters' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets system parameters to: +{{to_json params}} + +

setpriv

+ +--- +spec_version: "0.2.0" +title: Make an Account Privileged or Unprivileged +summary: '{{#if is_priv}}Make {{nowrap account}} privileged{{else}}Remove privileged status of {{nowrap account}}{{/if}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if is_priv}} +{{$action.account}} makes {{account}} privileged. +{{else}} +{{$action.account}} removes privileged status of {{account}}. +{{/if}} + +

setprods

+ +--- +spec_version: "0.2.0" +title: Set Block Producers +summary: 'Set block producer schedule' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} proposes a block producer schedule of: +{{#each schedule}} + 1. {{this.producer_name}} with a block signing key of {{this.block_signing_key}} +{{/each}} + +

unlinkauth

+ +--- +spec_version: "0.2.0" +title: Unlink Action from Permission +summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission. + +{{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}} + +

updateauth

+ +--- +spec_version: "0.2.0" +title: Modify Account Permission +summary: 'Add or update the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Modify, and create if necessary, the {{permission}} permission of {{account}} to have a parent permission of {{parent}} and the following authority: +{{to_json auth}} diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 01e85c02d..9f1d7f480 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -1,3 +1,3 @@ #include -EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(setparams)(reqauth)(setabi) ) +EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setprods)(setparams)(reqauth)(setabi) ) diff --git a/contracts/eosio.msig/CMakeLists.txt b/contracts/eosio.msig/CMakeLists.txt index 089587f28..0947ea9d0 100755 --- a/contracts/eosio.msig/CMakeLists.txt +++ b/contracts/eosio.msig/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.msig set_target_properties(eosio.msig PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.msig.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.msig.contracts.md @ONLY ) + +target_compile_options( eosio.msig PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in b/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in new file mode 100644 index 000000000..b9f3f35f8 --- /dev/null +++ b/contracts/eosio.msig/ricardian/eosio.msig.contracts.md.in @@ -0,0 +1,73 @@ +

approve

+ +--- +spec_version: "0.2.0" +title: Approve Proposed Transaction +summary: '{{nowrap level.actor}} approves the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{level.actor}} approves the {{proposal_name}} proposal proposed by {{proposer}} with the {{level.permission}} permission of {{level.actor}}. + +

cancel

+ +--- +spec_version: "0.2.0" +title: Cancel Proposed Transaction +summary: '{{nowrap canceler}} cancels the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{canceler}} cancels the {{proposal_name}} proposal submitted by {{proposer}}. + +

exec

+ +--- +spec_version: "0.2.0" +title: Execute Proposed Transaction +summary: '{{nowrap executer}} executes the {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{executer}} executes the {{proposal_name}} proposal submitted by {{proposer}} if the minimum required approvals for the proposal have been secured. + +

invalidate

+ +--- +spec_version: "0.2.0" +title: Invalidate All Approvals +summary: '{{nowrap account}} invalidates approvals on outstanding proposals' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{account}} invalidates all approvals on proposals which have not yet executed. + +

propose

+ +--- +spec_version: "0.2.0" +title: Propose Transaction +summary: '{{nowrap proposer}} creates the {{nowrap proposal_name}}' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{proposer}} creates the {{proposal_name}} proposal for the following transaction: +{{to_json trx}} + +The proposal requests approvals from the following accounts at the specified permission levels: +{{#each requested}} + + {{this.permission}} permission of {{this.actor}} +{{/each}} + +If the proposed transaction is not executed prior to {{trx.expiration}}, the proposal will automatically expire. + +

unapprove

+ +--- +spec_version: "0.2.0" +title: Unapprove Proposed Transaction +summary: '{{nowrap level.actor}} revokes the approval previously provided to {{nowrap proposal_name}} proposal' +icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ +--- + +{{level.actor}} revokes the approval previously provided at their {{level.permission}} permission level from the {{proposal_name}} proposal proposed by {{proposer}}. diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index de993ef05..e99eb37bd 100755 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -18,3 +18,7 @@ target_include_directories(rex.results set_target_properties(rex.results PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.rex") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.system.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.system.contracts.md @ONLY ) + +target_compile_options( eosio.system PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.system/ricardian/eosio.system.clauses.md b/contracts/eosio.system/ricardian/eosio.system.clauses.md new file mode 100644 index 000000000..19be74f81 --- /dev/null +++ b/contracts/eosio.system/ricardian/eosio.system.clauses.md @@ -0,0 +1,63 @@ +

UserAgreement

+ +User agreement for the chain can go here. + +

BlockProducerAgreement

+ +I, {{producer}}, hereby nominate myself for consideration as an elected block producer. + +If {{producer}} is selected to produce blocks by the system contract, I will sign blocks with {{producer_key}} and I hereby attest that I will keep this key secret and secure. + +If {{producer}} is unable to perform obligations under this contract I will resign my position by resubmitting this contract with the null producer key. + +I acknowledge that a block is 'objectively valid' if it conforms to the deterministic blockchain rules in force at the time of its creation, and is 'objectively invalid' if it fails to conform to those rules. + +{{producer}} hereby agrees to only use {{producer_key}} to sign messages under the following scenarios: + +* proposing an objectively valid block at the time appointed by the block scheduling algorithm; +* pre-confirming a block produced by another producer in the schedule when I find said block objectively valid; +* and, confirming a block for which {{producer}} has received pre-confirmation messages from more than two-thirds of the active block producers. + +I hereby accept liability for any and all provable damages that result from my: + +* signing two different block proposals with the same timestamp with {{producer_key}}; +* signing two different block proposals with the same block number with {{producer_key}}; +* signing any block proposal which builds off of an objectively invalid block; +* signing a pre-confirmation for an objectively invalid block; +* or, signing a confirmation for a block for which I do not possess pre-confirmation messages from more than two-thirds of the active block producers. + +I hereby agree that double-signing for a timestamp or block number in concert with two or more other block producers shall automatically be deemed malicious and cause {{producer}} to be subject to: + +* a fine equal to the past year of compensation received, +* immediate disqualification from being a producer, +* and/or other damages. + +An exception may be made if {{producer}} can demonstrate that the double-signing occurred due to a bug in the reference software; the burden of proof is on {{producer}}. + +I hereby agree not to interfere with the producer election process. I agree to process all producer election transactions that occur in blocks I create, to sign all objectively valid blocks I create that contain election transactions, and to sign all pre-confirmations and confirmations necessary to facilitate transfer of control to the next set of producers as determined by the system contract. + +I hereby acknowledge that more than two-thirds of the active block producers may vote to disqualify {{producer}} in the event {{producer}} is unable to produce blocks or is unable to be reached, according to criteria agreed to among block producers. + +If {{producer}} qualifies for and chooses to collect compensation due to votes received, {{producer}} will provide a public endpoint allowing at least 100 peers to maintain synchronization with the blockchain and/or submit transactions to be included. {{producer}} shall maintain at least one validating node with full state and signature checking and shall report any objectively invalid blocks produced by the active block producers. Reporting shall be via a method to be agreed to among block producers, said method and reports to be made public. + +The community agrees to allow {{producer}} to authenticate peers as necessary to prevent abuse and denial of service attacks; however, {{producer}} agrees not to discriminate against non-abusive peers. + +I agree to process transactions on a FIFO (first in, first out) best-effort basis and to honestly bill transactions for measured execution time. + +I {{producer}} agree not to manipulate the contents of blocks in order to derive profit from: the order in which transactions are included, or the hash of the block that is produced. + +I, {{producer}}, hereby agree to disclose and attest under penalty of perjury all ultimate beneficial owners of my business entity who own more than 10% and all direct shareholders. + +I, {{producer}}, hereby agree to cooperate with other block producers to carry out our respective and mutual obligations under this agreement, including but not limited to maintaining network stability and a valid blockchain. + +I, {{producer}}, agree to maintain a website hosted at {{url}} which contains up-to-date information on all disclosures required by this contract. + +I, {{producer}}, agree to set the location value of {{location}} such that {{producer}} is scheduled with minimal latency between my previous and next peer. + +I, {{producer}}, agree to maintain time synchronization within 10 ms of global atomic clock time, using a method agreed to among block producers. + +I, {{producer}}, agree not to produce blocks before my scheduled time unless I have received all blocks produced by the prior block producer. + +I, {{producer}}, agree not to publish blocks with timestamps more than 500ms in the future unless the prior block is more than 75% full by either NET or CPU bandwidth metrics. + +I, {{producer}}, agree not to set the RAM supply to more RAM than my nodes contain and to resign if I am unable to provide the RAM approved by more than two-thirds of active block producers, as shown in the system parameters. diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in new file mode 100644 index 000000000..e14489ae5 --- /dev/null +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -0,0 +1,653 @@ +

bidname

+ +--- +spec_version: "0.2.0" +title: Bid On a Premium Account Name +summary: '{{nowrap bidder}} bids on the premium account name {{nowrap newname}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{bidder}} bids {{bid}} on an auction to own the premium account name {{newname}}. + +{{bidder}} transfers {{bid}} to the system to cover the cost of the bid, which will be returned to {{bidder}} only if {{bidder}} is later outbid in the auction for {{newname}} by another account. + +If the auction for {{newname}} closes with {{bidder}} remaining as the highest bidder, {{bidder}} will be authorized to create the account with name {{newname}}. + +## Bid refund behavior + +If {{bidder}}’s bid on {{newname}} is later outbid by another account, {{bidder}} will be able to claim back the transferred amount of {{bid}}. The system will attempt to automatically do this on behalf of {{bidder}}, but the automatic refund may occasionally fail which will then require {{bidder}} to manually claim the refund with the bidrefund action. + +## Auction close criteria + +The system should automatically close the auction for {{newname}} if it satisfies the condition that over a period of two minutes the following two properties continuously hold: + +- no one has bid on {{newname}} within the last 24 hours; +- and, the value of the latest bid on {{newname}} is greater than the value of the bids on each of the other open auctions. + +Be aware that the condition to close the auction described above are sufficient but not necessary. The auction for {{newname}} cannot close unless both of the properties are simultaneously satisfied, but it may be closed without requiring the properties to hold for a period of 2 minutes. + +

bidrefund

+ +--- +spec_version: "0.2.0" +title: Claim Refund on Name Bid +summary: 'Claim refund on {{nowrap newname}} bid' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{bidder}} claims refund on {{newname}} bid after being outbid by someone else. + +

buyram

+ +--- +spec_version: "0.2.0" +title: Buy RAM +summary: '{{nowrap payer}} buys RAM on behalf of {{nowrap receiver}} by paying {{nowrap quant}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{payer}} buys RAM on behalf of {{receiver}} by paying {{quant}}. This transaction will incur a 0.5% fee out of {{quant}} and the amount of RAM delivered will depend on market rates. + +

buyrambytes

+ +--- +spec_version: "0.2.0" +title: Buy RAM +summary: '{{nowrap payer}} buys {{nowrap bytes}} bytes of RAM on behalf of {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{payer}} buys approximately {{bytes}} bytes of RAM on behalf of {{receiver}} by paying market rates for RAM. This transaction will incur a 0.5% fee and the cost will depend on market rates. + +

buyrex

+ +--- +spec_version: "0.2.0" +title: Buy REX Tokens +summary: '{{nowrap from}} buys REX tokens in exchange for {{nowrap amount}} and his vote stake increases by {{nowrap amount}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{amount}} is taken out of {{from}}’s REX fund and used to purchase REX tokens at the current market exchange rate. In order for the action to succeed, {{from}} must have voted for a proxy or at least 21 block producers. {{amount}} is added to {{from}}’s vote stake. + +A sell order of the purchased amount can only be initiated after waiting for the maturity period of 4 to 5 days to pass. Even then, depending on the market conditions, the initiated sell order may not be executed immediately. + +

canceldelay

+ +--- +spec_version: "0.2.0" +title: Cancel Delayed Transaction +summary: '{{nowrap canceling_auth.actor}} cancels a delayed transaction' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{canceling_auth.actor}} cancels the delayed transaction with id {{trx_id}}. + +

claimrewards

+ +--- +spec_version: "0.2.0" +title: Claim Block Producer Rewards +summary: '{{nowrap owner}} claims block and vote rewards' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{owner}} claims block and vote rewards from the system. + +

closerex

+ +--- +spec_version: "0.2.0" +title: Cleanup Unused REX Data +summary: 'Delete REX related DB entries and free associated RAM' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Delete REX related DB entries and free associated RAM for {{owner}}. + +To fully delete all REX related DB entries, {{owner}} must ensure that their REX balance and REX fund amounts are both zero and they have no outstanding loans. + +

cnclrexorder

+ +--- +spec_version: "0.2.0" +title: Cancel Scheduled REX Sell Order +summary: '{{nowrap owner}} cancels a scheduled sell order if not yet filled' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} cancels their open sell order. + +

consolidate

+ +--- +spec_version: "0.2.0" +title: Consolidate REX Maturity Buckets Into One +summary: 'Consolidate REX maturity buckets into one' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Consolidate REX maturity buckets into one bucket that {{owner}} will not be able to sell until 4 to 5 days later. + +

defcpuloan

+ +--- +spec_version: "0.2.0" +title: Withdraw from the Fund of a Specific CPU Loan +summary: '{{nowrap from}} transfers {{nowrap amount}} from the fund of CPU loan number {{nowrap loan_num}} back to REX fund' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{amount}} from the fund of CPU loan number {{loan_num}} back to REX fund. + +

defnetloan

+ +--- +spec_version: "0.2.0" +title: Withdraw from the Fund of a Specific NET Loan +summary: '{{nowrap from}} transfers {{nowrap amount}} from the fund of NET loan number {{nowrap loan_num}} back to REX fund' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{amount}} from the fund of NET loan number {{loan_num}} back to REX fund. + +

delegatebw

+ +--- +spec_version: "0.2.0" +title: Stake Tokens for NET and/or CPU +summary: 'Stake tokens for NET and/or CPU and optionally transfer ownership' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{#if transfer}} {{from}} stakes on behalf of {{receiver}} {{stake_net_quantity}} for NET bandwidth and {{stake_cpu_quantity}} for CPU bandwidth. + +Staked tokens will also be transferred to {{receiver}}. The sum of these two quantities will be deducted from {{from}}’s liquid balance and add to the vote weight of {{receiver}}. +{{else}} +{{from}} stakes to self and delegates to {{receiver}} {{stake_net_quantity}} for NET bandwidth and {{stake_cpu_quantity}} for CPU bandwidth. + +The sum of these two quantities add to the vote weight of {{from}}. +{{/if}} + +

deleteauth

+ +--- +spec_version: "0.2.0" +title: Delete Account Permission +summary: 'Delete the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Delete the {{permission}} permission of {{account}}. + +

deposit

+ +--- +spec_version: "0.2.0" +title: Deposit Into REX Fund +summary: 'Add to {{nowrap owner}}’s REX fund by transferring {{nowrap amount}} from {{nowrap owner}}’s liquid balance' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Transfer {{amount}} from {{owner}}’s liquid balance to {{owner}}’s REX fund. All proceeds and expenses related to REX are added to or taken out of this fund. + +

fundcpuloan

+ +--- +spec_version: "0.2.0" +title: Deposit into the Fund of a Specific CPU Loan +summary: '{{nowrap from}} funds a CPU loan' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{payment}} from REX fund to the fund of CPU loan number {{loan_num}} in order to be used in loan renewal at expiry. {{from}} can withdraw the total balance of the loan fund at any time. + +

fundnetloan

+ +--- +spec_version: "0.2.0" +title: Deposit into the Fund of a Specific NET Loan +summary: '{{nowrap from}} funds a NET loan' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} transfers {{payment}} from REX fund to the fund of NET loan number {{loan_num}} in order to be used in loan renewal at expiry. {{from}} can withdraw the total balance of the loan fund at any time. + +

init

+ +--- +spec_version: "0.2.0" +title: Initialize System Contract +summary: 'Initialize system contract' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +Initialize system contract. The core token symbol will be set to {{core}}. + +

linkauth

+ +--- +spec_version: "0.2.0" +title: Link Action to Permission +summary: '{{nowrap account}} sets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract to {{nowrap requirement}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} sets the minimum required permission for the {{#if type}}{{type}} action of the{{/if}} {{code}} contract to {{requirement}}. + +{{#if type}}{{else}}Any links explicitly associated to specific actions of {{code}} will take precedence.{{/if}} + +

newaccount

+ +--- +spec_version: "0.2.0" +title: Create New Account +summary: '{{nowrap creator}} creates a new account with the name {{nowrap name}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{creator}} creates a new account with the name {{name}} and the following permissions: + +owner permission with authority: +{{to_json owner}} + +active permission with authority: +{{to_json active}} + +

mvfrsavings

+ +--- +spec_version: "0.2.0" +title: Unlock REX Tokens +summary: '{{nowrap owner}} unlocks REX Tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} unlocks {{rex}} by moving it out of the REX savings bucket. The unlocked REX tokens cannot be sold until 4 to 5 days later. + +

mvtosavings

+ +--- +spec_version: "0.2.0" +title: Lock REX Tokens +summary: '{{nowrap owner}} locks REX Tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{owner}} locks {{rex}} by moving it into the REX savings bucket. The locked REX tokens cannot be sold directly and will have to be unlocked explicitly before selling. + +

refund

+ +--- +spec_version: "0.2.0" +title: Claim Unstaked Tokens +summary: 'Return previously unstaked tokens to {{nowrap owner}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Return previously unstaked tokens to {{owner}} after the unstaking period has elapsed. + +

regproducer

+ +--- +spec_version: "0.2.0" +title: Register as a Block Producer Candidate +summary: 'Register {{nowrap producer}} account as a block producer candidate' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +Register {{producer}} account as a block producer candidate. + +{{$clauses.BlockProducerAgreement}} + +

regproxy

+ +--- +spec_version: "0.2.0" +title: Register/unregister as a Proxy +summary: 'Register/unregister {{nowrap proxy}} as a proxy account' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{#if isproxy}} +{{proxy}} registers as a proxy that can vote on behalf of accounts that appoint it as their proxy. +{{else}} +{{proxy}} unregisters as a proxy that can vote on behalf of accounts that appoint it as their proxy. +{{/if}} + +

rentcpu

+ +--- +spec_version: "0.2.0" +title: Rent CPU Bandwidth for 30 Days +summary: '{{nowrap from}} pays {{nowrap loan_payment}} to rent CPU bandwidth for {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} pays {{loan_payment}} to rent CPU bandwidth on behalf of {{receiver}} for a period of 30 days. + +{{loan_payment}} is taken out of {{from}}’s REX fund. The market price determines the number of tokens to be staked to {{receiver}}’s CPU resources. In addition, {{from}} provides {{loan_fund}}, which is also taken out of {{from}}’s REX fund, to be used for automatic renewal of the loan. + +At expiration, if the loan has less funds than {{loan_payment}}, it is closed and lent tokens that have been staked are taken out of {{receiver}}’s CPU bandwidth. Otherwise, it is renewed at the market price at the time of renewal, that is, the number of staked tokens is recalculated and {{receiver}}’s CPU bandwidth is updated accordingly. {{from}} can fund or defund a loan at any time before expiration. When the loan is closed, {{from}} is refunded any tokens remaining in the loan fund. + +

rentnet

+ +--- +spec_version: "0.2.0" +title: Rent NET Bandwidth for 30 Days +summary: '{{nowrap from}} pays {{nowrap loan_payment}} to rent NET bandwidth for {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} pays {{loan_payment}} to rent NET bandwidth on behalf of {{receiver}} for a period of 30 days. + +{{loan_payment}} is taken out of {{from}}’s REX fund. The market price determines the number of tokens to be staked to {{receiver}}’s NET resources for 30 days. In addition, {{from}} provides {{loan_fund}}, which is also taken out of {{from}}’s REX fund, to be used for automatic renewal of the loan. + +At expiration, if the loan has less funds than {{loan_payment}}, it is closed and lent tokens that have been staked are taken out of {{receiver}}’s NET bandwidth. Otherwise, it is renewed at the market price at the time of renewal, that is, the number of staked tokens is recalculated and {{receiver}}’s NET bandwidth is updated accordingly. {{from}} can fund or defund a loan at any time before expiration. When the loan is closed, {{from}} is refunded any tokens remaining in the loan fund. + +

rexexec

+ +--- +spec_version: "0.2.0" +title: Perform REX Maintenance +summary: 'Process sell orders and expired loans' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Performs REX maintenance by processing a maximum of {{max}} REX sell orders and expired loans. Any account can execute this action. + +

rmvproducer

+ +--- +spec_version: "0.2.0" +title: Forcibly Unregister a Block Producer Candidate +summary: '{{nowrap producer}} is unregistered as a block producer candidate' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} unregisters {{producer}} as a block producer candidate. {{producer}} account will retain its votes and those votes can change based on voter stake changes or votes removed from {{producer}}. However new voters will not be able to vote for {{producer}} while it remains unregistered. + +

sellram

+ +--- +spec_version: "0.2.0" +title: Sell RAM From Account +summary: 'Sell unused RAM from {{nowrap account}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +Sell {{bytes}} bytes of unused RAM from account {{account}} at market price. This transaction will incur a 0.5% fee on the proceeds which depend on market rates. + +

sellrex

+ +--- +spec_version: "0.2.0" +title: Sell REX Tokens in Exchange for EOS +summary: '{{nowrap from}} sells {{nowrap rex}} tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from}} initiates a sell order to sell {{rex}} tokens at the market exchange rate during the time at which the order is ultimately executed. If {{from}} already has an open sell order in the sell queue, {{rex}} will be added to the amount of the sell order without change the position of the sell order within the queue. Once the sell order is executed, proceeds are added to {{from}}’s REX fund, the value of sold REX tokens is deducted from {{from}}’s vote stake, and votes are updated accordingly. + +Depending on the market conditions, it may not be possible to fill the entire sell order immediately. In such a case, the sell order is added to the back of a sell queue. A sell order at the front of the sell queue will automatically be executed when the market conditions allow for the entire order to be filled. Regardless of the market conditions, the system is designed to execute this sell order within 30 days. {{from}} can cancel the order at any time before it is filled using the cnclrexorder action. + +

setabi

+ +--- +spec_version: "0.2.0" +title: Deploy Contract ABI +summary: 'Deploy contract ABI on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy the ABI file associated with the contract on account {{account}}. + +

setacctcpu

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the CPU Quota of Account +summary: 'Explicitly manage the CPU bandwidth quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value cpu_weight}} +Explicitly manage the CPU bandwidth quota of account {{account}} by pinning it to a weight of {{cpu_weight}}. + +{{account}} can stake and unstake, however, it will not change their CPU bandwidth quota as long as it remains pinned. +{{else}} +Unpin the CPU bandwidth quota of account {{account}}. The CPU bandwidth quota of {{account}} will be driven by the current tokens staked for CPU bandwidth by {{account}}. +{{/if_has_value}} + +

setacctnet

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the NET Quota of Account +summary: 'Explicitly manage the NET bandwidth quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value net_weight}} +Explicitly manage the network bandwidth quota of account {{account}} by pinning it to a weight of {{net_weight}}. + +{{account}} can stake and unstake, however, it will not change their NET bandwidth quota as long as it remains pinned. +{{else}} +Unpin the NET bandwidth quota of account {{account}}. The NET bandwidth quota of {{account}} will be driven by the current tokens staked for NET bandwidth by {{account}}. +{{/if_has_value}} + +

setacctram

+ +--- +spec_version: "0.2.0" +title: Explicitly Manage the RAM Quota of Account +summary: 'Explicitly manage the RAM quota of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if_has_value ram_bytes}} +Explicitly manage the RAM quota of account {{account}} by pinning it to {{ram_bytes}} bytes. + +{{account}} can buy and sell RAM, however, it will not change their RAM quota as long as it remains pinned. +{{else}} +Unpin the RAM quota of account {{account}}. The RAM quota of {{account}} will be driven by the current RAM holdings of {{account}}. +{{/if_has_value}} + +

setalimits

+ +--- +spec_version: "0.2.0" +title: Adjust Resource Limits of Account +summary: 'Adjust resource limits of account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} updates {{account}}’s resource limits to have a RAM quota of {{ram_bytes}} bytes, a NET bandwidth quota of {{net_weight}} and a CPU bandwidth quota of {{cpu_weight}}. + +

setcode

+ +--- +spec_version: "0.2.0" +title: Deploy Contract Code +summary: 'Deploy contract code on account {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Deploy compiled contract code to the account {{account}}. + +

setparams

+ +--- +spec_version: "0.2.0" +title: Set System Parameters +summary: 'Set System Parameters' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets system parameters to: +{{to_json params}} + +

setpriv

+ +--- +spec_version: "0.2.0" +title: Make an Account Privileged or Unprivileged +summary: '{{#if is_priv}}Make {{nowrap account}} privileged{{else}}Remove privileged status of {{nowrap account}}{{/if}}' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{#if is_priv}} +{{$action.account}} makes {{account}} privileged. +{{else}} +{{$action.account}} removes privileged status of {{account}}. +{{/if}} + +

setram

+ +--- +spec_version: "0.2.0" +title: Configure the Available RAM +summary: 'Configure the available RAM' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} configures the available RAM to {{max_ram_size}} bytes. + +

setramrate

+ +--- +spec_version: "0.2.0" +title: Set the Rate of Increase of RAM +summary: 'Set the rate of increase of RAM per block' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} sets the rate of increase of RAM to {{bytes_per_block}} bytes/block. + +

setrex

+ +--- +spec_version: "0.2.0" +title: Adjust REX Pool Virtual Balance +summary: 'Adjust REX Pool Virtual Balance' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} adjusts REX loan rate by setting REX pool virtual balance to {{balance}}. No token transfer or issue is executed in this action. + +

undelegatebw

+ +--- +spec_version: "0.2.0" +title: Unstake Tokens for NET and/or CPU +summary: 'Unstake tokens for NET and/or CPU from {{nowrap receiver}}' +icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ +--- + +{{from}} unstakes from {{receiver}} {{unstake_net_quantity}} for NET bandwidth and {{unstake_cpu_quantity}} for CPU bandwidth. + +The sum of these two quantities will be removed from the vote weight of {{receiver}} and will be made available to {{from}} after an uninterrupted 3 day period without further unstaking by {{from}}. After the uninterrupted 3 day period passes, the system will attempt to automatically return the funds to {{from}}’s regular token balance. However, this automatic refund may occasionally fail which will then require {{from}} to manually claim the funds with the refund action. + +

unlinkauth

+ +--- +spec_version: "0.2.0" +title: Unlink Action from Permission +summary: '{{nowrap account}} unsets the minimum required permission for the {{#if type}}{{nowrap type}} action of the{{/if}} {{nowrap code}} contract' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +{{account}} removes the association between the {{#if type}}{{type}} action of the{{/if}} {{code}} contract and its minimum required permission. + +{{#if type}}{{else}}This will not remove any links explicitly associated to specific actions of {{code}}.{{/if}} + +

unregprod

+ +--- +spec_version: "0.2.0" +title: Unregister as a Block Producer Candidate +summary: '{{nowrap producer}} unregisters as a block producer candidate' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{producer}} unregisters as a block producer candidate. {{producer}} account will retain its votes and those votes can change based on voter stake changes or votes removed from {{producer}}. However new voters will not be able to vote for {{producer}} while it remains unregistered. + +

unstaketorex

+ +--- +spec_version: "0.2.0" +title: Buy REX Tokens Using Staked Tokens +summary: '{{nowrap owner}} buys REX tokens in exchange for tokens currently staked to NET and/or CPU' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +{{from_net}} and {{from_cpu}} are withdrawn from {{receiver}}’s NET and CPU bandwidths respectively. These funds are used to purchase REX tokens at the current market exchange rate. In order for the action to succeed, {{owner}} must have voted for a proxy or at least 21 block producers. + +A sell order of the purchased amount can only be initiated after waiting for the maturity period of 4 to 5 days to pass. Even then, depending on the market conditions, the initiated sell order may not be executed immediately. + +

updateauth

+ +--- +spec_version: "0.2.0" +title: Modify Account Permission +summary: 'Add or update the {{nowrap permission}} permission of {{nowrap account}}' +icon: @ICON_BASE_URL@/@ACCOUNT_ICON_URI@ +--- + +Modify, and create if necessary, the {{permission}} permission of {{account}} to have a parent permission of {{parent}} and the following authority: +{{to_json auth}} + +

updaterex

+ +--- +spec_version: "0.2.0" +title: Update REX Owner Vote Weight +summary: 'Update vote weight to current value of held REX tokens' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Update vote weight of {{owner}} account to current value of held REX tokens. + +

updtrevision

+ +--- +spec_version: "0.2.0" +title: Update System Contract Revision Number +summary: 'Update system contract revision number' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{$action.account}} advances the system contract revision number to {{revision}}. + +

voteproducer

+ +--- +spec_version: "0.2.0" +title: Vote for Block Producers +summary: '{{nowrap voter}} votes for {{#if proxy}}the proxy {{nowrap proxy}}{{else}}up to 30 block producer candidates{{/if}}' +icon: @ICON_BASE_URL@/@VOTING_ICON_URI@ +--- + +{{#if proxy}} +{{voter}} votes for the proxy {{proxy}}. +At the time of voting the full weight of voter’s staked (CPU + NET) tokens will be cast towards each of the producers voted by {{proxy}}. +{{else}} +{{voter}} votes for the following block producer candidates: + +{{#each producers}} + + {{this}} +{{/each}} + +At the time of voting the full weight of voter’s staked (CPU + NET) tokens will be cast towards each of the above producers. +{{/if}} + +

withdraw

+ +--- +spec_version: "0.2.0" +title: Withdraw from REX Fund +summary: 'Withdraw {{nowrap amount}} from {{nowrap owner}}’s REX fund by transferring to {{owner}}’s liquid balance' +icon: @ICON_BASE_URL@/@REX_ICON_URI@ +--- + +Withdraws {{amount}} from {{owner}}’s REX fund and transfer them to {{owner}}’s liquid balance. diff --git a/contracts/eosio.token/CMakeLists.txt b/contracts/eosio.token/CMakeLists.txt index 25c56b51e..cf53f62cd 100755 --- a/contracts/eosio.token/CMakeLists.txt +++ b/contracts/eosio.token/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.token set_target_properties(eosio.token PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.token.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.token.contracts.md @ONLY ) + +target_compile_options( eosio.token PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.token/ricardian/eosio.token.contracts.md.in b/contracts/eosio.token/ricardian/eosio.token.contracts.md.in new file mode 100644 index 000000000..f050eec77 --- /dev/null +++ b/contracts/eosio.token/ricardian/eosio.token.contracts.md.in @@ -0,0 +1,95 @@ +

close

+ +--- +spec_version: "0.2.0" +title: Close Token Balance +summary: 'Close {{nowrap owner}}’s zero quantity balance' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{owner}} agrees to close their zero quantity balance for the {{symbol_to_symbol_code symbol}} token. + +RAM will be refunded to the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. + +

create

+ +--- +spec_version: "0.2.0" +title: Create New Token +summary: 'Create a new token' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{$action.account}} agrees to create a new token with symbol {{asset_to_symbol_code maximum_supply}} to be managed by {{issuer}}. + +This action will not result any any tokens being issued into circulation. + +{{issuer}} will be allowed to issue tokens into circulation, up to a maximum supply of {{maximum_supply}}. + +RAM will deducted from {{$action.account}}’s resources to create the necessary records. + +

issue

+ +--- +spec_version: "0.2.0" +title: Issue Tokens into Circulation +summary: 'Issue {{nowrap quantity}} into circulation and transfer into {{nowrap to}}’s account' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +The token manager agrees to issue {{quantity}} into circulation, and transfer it into {{to}}’s account. + +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} + +If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, or the token manager does not have a balance for {{asset_to_symbol_code quantity}}, the token manager will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from the token manager’s resources to create the necessary records. + +This action does not allow the total quantity to exceed the max allowed supply of the token. + +

open

+ +--- +spec_version: "0.2.0" +title: Open Token Balance +summary: 'Open a zero quantity balance for {{nowrap owner}}' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +{{ram_payer}} agrees to establish a zero quantity balance for {{owner}} for the {{symbol_to_symbol_code symbol}} token. + +If {{owner}} does not have a balance for {{symbol_to_symbol_code symbol}}, {{ram_payer}} will be designated as the RAM payer of the {{symbol_to_symbol_code symbol}} token balance for {{owner}}. As a result, RAM will be deducted from {{ram_payer}}’s resources to create the necessary records. + +

retire

+ +--- +spec_version: "0.2.0" +title: Remove Tokens from Circulation +summary: 'Remove {{nowrap quantity}} from circulation' +icon: @ICON_BASE_URL@/@TOKEN_ICON_URI@ +--- + +The token manager agrees to remove {{quantity}} from circulation, taken from their own account. + +{{#if memo}} There is a memo attached to the action stating: +{{memo}} +{{/if}} + +

transfer

+ +--- +spec_version: "0.2.0" +title: Transfer Tokens +summary: 'Send {{nowrap quantity}} from {{nowrap from}} to {{nowrap to}}' +icon: @ICON_BASE_URL@/@TRANSFER_ICON_URI@ +--- + +{{from}} agrees to send {{quantity}} to {{to}}. + +{{#if memo}}There is a memo attached to the transfer stating: +{{memo}} +{{/if}} + +If {{from}} is not already the RAM payer of their {{asset_to_symbol_code quantity}} token balance, {{from}} will be designated as such. As a result, RAM will be deducted from {{from}}’s resources to refund the original RAM payer. + +If {{to}} does not have a balance for {{asset_to_symbol_code quantity}}, {{from}} will be designated as the RAM payer of the {{asset_to_symbol_code quantity}} token balance for {{to}}. As a result, RAM will be deducted from {{from}}’s resources to create the necessary records. diff --git a/contracts/eosio.wrap/CMakeLists.txt b/contracts/eosio.wrap/CMakeLists.txt index 6d064bff7..27d429194 100755 --- a/contracts/eosio.wrap/CMakeLists.txt +++ b/contracts/eosio.wrap/CMakeLists.txt @@ -7,3 +7,7 @@ target_include_directories(eosio.wrap set_target_properties(eosio.wrap PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.wrap.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.wrap.contracts.md @ONLY ) + +target_compile_options( eosio.wrap PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) diff --git a/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in b/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in new file mode 100644 index 000000000..8077a3472 --- /dev/null +++ b/contracts/eosio.wrap/ricardian/eosio.wrap.contracts.md.in @@ -0,0 +1,13 @@ +

exec

+ +--- +spec_version: "0.2.0" +title: Privileged Execute +summary: '{{nowrap executer}} executes a transaction while bypassing authority checks' +icon: @ICON_BASE_URL@/@ADMIN_ICON_URI@ +--- + +{{executer}} executes the following transaction while bypassing authority checks: +{{to_json trx}} + +{{$action.account}} must also authorize this action. diff --git a/contracts/icons/account.png b/contracts/icons/account.png new file mode 100644 index 0000000000000000000000000000000000000000..7686587824ac663ffb79f3ee30d06821a26e6c26 GIT binary patch literal 3795 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 JPDHLkV1nnf{$~IH literal 0 HcmV?d00001 diff --git a/contracts/icons/account.svg b/contracts/icons/account.svg new file mode 100644 index 000000000..511f06499 --- /dev/null +++ b/contracts/icons/account.svg @@ -0,0 +1 @@ +Account \ No newline at end of file diff --git a/contracts/icons/admin.png b/contracts/icons/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..ae95364725ed2e9f6143044631d2ff136201fa2b GIT binary patch literal 2937 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 V=0Y3_AOE>PN6S$2rMg|je*nyqJZk^| literal 0 HcmV?d00001 diff --git a/contracts/icons/admin.svg b/contracts/icons/admin.svg new file mode 100644 index 000000000..fbc057179 --- /dev/null +++ b/contracts/icons/admin.svg @@ -0,0 +1 @@ +Admin \ No newline at end of file diff --git a/contracts/icons/multisig.png b/contracts/icons/multisig.png new file mode 100644 index 0000000000000000000000000000000000000000..00fa7564c88ea2785f53d641f150b32ec68a7b47 GIT binary patch literal 1411 zcmZ`%doqG{65Om;k{$VjOf%}jL|q`{EKZ_{CyDS4zk z(jazeJThn}$`&WHgx7r|KPRBU)0;w2-ok=^j-Q{e~v!@bbksTMV)7UQT}8uv~^<) zI$fbW_lQS}W+oVL*;zwR1mJXycr06F{D&lRfmxK^r3bp`3GuFvkN6LW)?nAOQ93fq z{NKv|vE^}24I13&Wh`o#ToS$=*UB6&S+wz!O>_dYbMCipI)V7ntxsjw*ty)zAVSf@ z&_Dim2n9$=tBf-Io~;tQ+n($H@(}~A^u%D4Pc8_u^V;B0OaS5lReOLObZmOx;;G}#;8*|+;c2be4I3`gN zhA*dU-77eHcf@h4FR%G z^aZ0lMorCFr^CEtC{Ygw9Xv9H7uht5$`Kn7A&0(ix?>tq_wz@c;Czv+$H0B<@fC5_ z9^O&Zp-ZogJ!__ydf~*kd1zwdI~!h10hy_Vp5G`5#au9wFm3rbh33#LfS1xF(Rp3d zJI;SCx#J!;ZMoY>*CG>nzF~t|Qfl^Un0IA!!>OAI5=x`k}(g&Oz9Nt*cBh=0VG`vkBgj_>ji16&N=NetoxA@plV?sUDV0z&_Nds zzHBn;p*55~yBEcF0$Ep$~xv06jiA|H79p$LBE)8|Qx+v=u(O)N^t zRtH#rkk{syuG>An9-Go<{SB_$5xc_H^jz1y*RJg1-A7NY4@lW*x7xn&+;8m~?QvN>T-E3}C(Y{}`$>K-Ikm~!K&AM#mwr|S`X<*0X7g}z{(qH(X( z31&CWc{@Zxd}+R_Q0^=S3M|f29sr(*nyMR5^)AyiJZyIQWmk5p1~sg^zjorepylGp zgj$P1Xqrvaelf)=g)FDMUFW5j)@VI^UT~$UKB*WO%k%fCyfRP-|G?X8V*)#&nfEj6 YBtQ`z6CivXCH{CNh3rMDa-pC88^Gy0WB>pF literal 0 HcmV?d00001 diff --git a/contracts/icons/multisig.svg b/contracts/icons/multisig.svg new file mode 100644 index 000000000..d9167fb2c --- /dev/null +++ b/contracts/icons/multisig.svg @@ -0,0 +1 @@ +Multi Sig \ No newline at end of file diff --git a/contracts/icons/resource.png b/contracts/icons/resource.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1bd127de7b7adb74c5d5765db70a036fd0aa8f GIT binary patch literal 1913 zcmZ`)X;72r7Jk3v3rUbAhzdcFutg}ftU*A)ghh$S9s{zJkjPRZ5D~&=hYv_)5n2{6 z?uyE-vKAEx2$cwEr6L6t1QZDr1=%H(2(sKvXYSnktNTnXHn@iK#cQN17U1Bia1wiuy-wzn?2E zO-ntqxw)ymt=dhtt`hI#;VVnOFkn!9fenCME8UsKNE(_M9=v~(qySh)w|l>qrVZJg zWJY=qo{cPeD#^dHs%8Ln%;nhGqDbIxAel~zjS$&rI~(y%4F0VbW!k&0TgYU^kI^7QI zo*6`4>LJIf#+h74bp(8*sJsY1!NVw#taO-eetMQ@tT+L-otSu);kn-hVIP10>p&D- z3f(ul5tG}Q_^k1w;Sgj_HPvB`hA@^T9_6g|-^@hd`i`iKiI3SI`ntBxSRW99d3O=q zP5Y*IHc25^-aZHs&RbzU_E+!a%=;B!6cz$hjRN~GWCf%jDS&qU;SLoZ8BL{^S$aMJ zvG_a2q=_yQ)9i6ctQ@I7HuI;9O=%r|ui>TGwPKO6hz4YLz4g#>Mbg>nB%;Krc;k zR%ztmV@_fbb&zA*#|GXLy9WX(st#$xl9iKl-;X;oRU=Wg!l=im;~e%!TV7u)2*HSA zQSEcc+%3+V}|AVxANkq;~ra21-~uijQef``8a|4 z&-&>(->x)nJ4`Nvz8<3-<7@ax=_uSgo-XnV9yzzx$BAQd2|&#x=RFpP%){dFU4g z11agtk9rcj@~uLuaHTHZXKVOT%3c;JGhib60d6~$g|)86Bbc56s5^jyR-C4nn8R{BxO?@e^c|@teZ#tpFnYf3RS&Rs##B z%BcGvOhC!--W#CfiktR-Pu<@K&lU2b6nVw2ED@3mPG;xqYtw{874!0{fhjgw&M^!U zj%EKc(i?r){I2GM-J;jr%Y{%&>tmvt=)AdZyc2S#U6Ez`1{~7EinU@8T0d-9ZGU%D zSUt-X8aJs$H=l|QrIbPobD(7Q7nS=&`YmVoJcrNkYaiBSJ4N+EnJG78OmCF zZzz@pBbvzmLMdv80n$wSGfzd7Z0|j}&X8gk__t4`IjLr_pJ*%1xf7|&sZRZ1eAKgfsSDGj%m`;!J#Cf65piZ5<5Rj8_2@Y8)GI^_-~#s_AB12g`?0(nO|i|= z6Ud<^(@2>m-riQ(?mte8aom~M;W`cD5rF##;vmb`SZ9cY|AMnmyAqUY7IRlA zQBl*e^=#?A5N5W3!wvOd3raS|O&oszyqWP%t4 lQzThj4saQu7QLp*0xy<3x9!Ue2$20bKzH$Qu5n~#{0CM4EzSS{ literal 0 HcmV?d00001 diff --git a/contracts/icons/resource.svg b/contracts/icons/resource.svg new file mode 100644 index 000000000..4a4755928 --- /dev/null +++ b/contracts/icons/resource.svg @@ -0,0 +1 @@ +Resource \ No newline at end of file diff --git a/contracts/icons/rex.png b/contracts/icons/rex.png new file mode 100644 index 0000000000000000000000000000000000000000..b43ee27fcf6180649c35b0739a74e37bc34d08ea GIT binary patch literal 2770 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 literal 0 HcmV?d00001 diff --git a/contracts/icons/rex.svg b/contracts/icons/rex.svg new file mode 100644 index 000000000..99f77f373 --- /dev/null +++ b/contracts/icons/rex.svg @@ -0,0 +1 @@ +Rex \ No newline at end of file diff --git a/contracts/icons/token.png b/contracts/icons/token.png new file mode 100644 index 0000000000000000000000000000000000000000..445188a0247749231e2de8832ac651a32a9a6c88 GIT binary patch literal 4268 zcmb7oX*d*q*!6GBV5~9rC5FZpAzLIGvX2n5?~MFO_MMESgo^A-*_EBL??Yr~vhPG? zY>|B{Pw&U~+w;d%Q$s}`0LVWI0dVL)a49n}{0D5_ zswUnBZjRo5ww_p^)Pk%mSUq)ER0-;Ya5|Kv8jnUlGu z0AG2!9ROGMG*y%g{b#oJR=e%NkTJxv78Y111BeGA&ekumw{`I;dYHHjAx{s}-7Ln}3Bt(KS|&0lveF zRY=-S#sxQ>@39v|_5x+)exu`$3b2wo|H?{Df`7&`{Ffsl%%noASW*f8dQGLKsRC>55%1;(oNnx6AZb)7ashKrZ>mKXbS@7YLxj;) z4m^-yu$ z$WxjJKWoZp=__S<$ubYEKqVKDo@R03=APv>X_bPsYu z1-|I3qiaU2J?$>7nSY?R*O748{Adi$>1oZH_Hr4o$?Q#vdmMts&hT-NM$e<)UT5T4 z!4M|qzD)|5fTF1{x`YEQ5{asZ><{Q63kBpVs!ig&E(@|b&}ng(4tl55%h z8q9G8lOZ^`zbKfCKP@H2{5MOFBzN#w;N9J0@%qa>b3K709Q5%s*Cg`--@%K0rZ!EQ z#>_3Q7PLaDd?+S)w+ETiv6c|WfP{Fi?GWE{S8E}Dv`W6fxsl={Mv9XG(Q0wH8QUU3 zDPlV-177o#mB%cE@E1KWe3MhJ?Lq}MnmoVRqaeP`6EL#`NIc?2zU$!WPVGB_Ht!uY z=QZ=MvcMPTt2-|^rHkb)RVwC~iMa=9xQ$0*u8s{3nGtEpY@t$M5enRa zGXKm}vumTg_F{KKOW0(7oDXoan(rd;^`n|(NOeYXDfo(3CQgu*sgxpbk1-q2UCMJU zh~`khBP|FY?wg3%PUhlornh47b6^PZ|)E{8;|a zwdbos!H1(!? zE8va20=uy4d$2{UV6TCpi$AArCG43BoZ6&fz;vLX`wjP*j3Dwd@i0e)g1}(3!_H_6 zT%9MQZ-Y6Vz(!H`S{CU!U~`7TKOC9X;?%l%<{y2fj2^UMU>XU%#p11F?6a+1oHGB3FsIu%-@fM|sDW!?HIeU*CpDLQWRP9~wk#KNEcI%; zT-*{6Q2DmnTJ}h0Lx~0|U~bHZH((4+20Dn3ya^K9x94%~lN40Z)TG{i;mV6OJ_l=P zp=XW4lvi!~p2|b3e7kK`*9RTCeJ1sfeuZ2k-{|NQR1J(c>KTa~{J7pED%WSd3zQo=?8?17P8E`>wN5slV41hFp-g z1O^oji=35)bKm5P@u>JDwIkY`_PA-u$&Bv0Y~EBcfm1`!V;mhA*U7;~i%-HlNms!% z7a0CL%qgRR#JIgC@Hu|yqyMZ@KJ(fV_=OPWh78zv72P{>m z&$Px6BGhqYc&o#?$ix5*q3fG@$&-|Ng1Gvrp3^S1w=#3whz)g|%EUCIBT%CQK=2hhsU z->NImcwCtmeqZf9Iqpl3RhPMw!GZeqOg`(xJY`}paIfMH`mdq+OO4_Ul>d+}Tu$G_ zN8la{ZBn5^quyOrSQ}%4TOZkopE-N=Y`#9mRU7_632a$RXJX7J^v%qbU)&x^f#9qe z$|jGt6xy#EAQI(3#;2;62<)u{XbrMbn z+Ziqbe?Q>{mrLEvm2_P`nG#*x70!tx6LXanLEB8%*SEQTzg^8G4PJiPIP>*2WtXb~ zhUz}5EqM3hSFknd3En%sX#E#mo&-|Gqs}FwONSDqhF<2IWIjC6=^08DbL?`tjf+QUHF!065gcuHW{b3SQPg z?R=f$nMXH&yxHR@qtz+mPbk+jr&!~;@#nFnz7t6V8Y!bS%t>0ZE^UzfYdV3fd44_9 zUAZ9-m9izsw2q^>cEI19TgNNhY%yBzhl*r&{es$OWOFcVp5eQ&kKJVbpdz!q~l2G*7Lj& z{MS2TrWD^|)N~R>V|s7WeTRBIt8(Iodk^040$u9zMI@6iy`n|lG=2H-o+A&VSjA{$ z;)PI#k_~g}@p5R|qeUP*2=C(LP`{Puxea))^EpY# z0Z4^veeYKJ^U>qFQ;gg7?91cAa|6X4atxe>0R4oHZh2c~th#~yb2IfZM>NTgydmH& zh2=R@1={x=YI6G@VnIWielppQSWu)^z;r)Ln^{olMB@-uxc(4~Bb2XXP?7u`FK7TjS-H9S3yT zn=^m)Mfup~hr>5vYELxJk_6KX*I%djn~I(x{eso9bL}UU=D+5jmq|HQ8J95fWnO=H zEom5&OFUnhVjFwJeB161Um#~!<($i&nUg*fpOFy5uGZF`sbi;c3Q-qd{`$A)otWf2 z4PhpF34?(;gkt(gcv6_@fYnuDaV<;02LA*{sPy9QpSWk!IY&XsFtcq@` z`53dhM^XdV9~ApcY|@u(wO6FAqVGt2;!WIbDq3I@986_!2ZEICkH7uT#ydewJvN{wdyWOC3iM>?NTUhH=0JP7lQ6dG1htW^pk@ux>JOsKRj zMoGs$%<;YdvtFN`(Xq-AS<%gxt9OFQO9(C&@<|5qID;fW;i>gI*(_``Hq8g3T{8t zdngpTX5G8-P11=C9$!dXuoyj8&ZoUHZetsQF6T&%6l4#`fzD4*XKY4GTj z<}wt`2)ni2Gpv?u(ANl+z5Fg)Z>FGLleyS+!noQe#_}cVV%(_G^#_&eL|}@IEcYfy zV|y{q_7C?H`grRPq#J<>y6(iNd$7wC3~DVg=D#;QHoxM=B}rp(rcZWV_}{uYzyGOw z5^5%(y3sf-%vMSdeeu@kDuc|WwkiUVu`DmtPpv1xZTa0aEA%~clqPe>tu7W;CCAh1 zGcn_MvVD;YJba|mPO@^o<|Q=t3X#CBGguW;IOw=J;$v3O>8W!8ZM&iVydip_Z-Xh$ z`(%I_$FG})en|w9&yj384DOsgfgsUI|(o41$+C#M5S=lkf@M$U1mYh3e zL?LBYQJL1UR`Pd3KRd4t>z?M*s;k}AD|ap=in>Qh(T)3(0do#; zFLAxK-t9Tu5R*M9k_k(7RVRt4?m)WQOS_o~y;ZA33kS}c z?xcR`DdmD`F93=WE9Q4PUKaIGLzXc)+LiDAAm-!4;z)7?u|1h>chzWuIDs{5ODAoL zJ2mIN9%vJMu*Amv-qp{(N1hYsM)#yD5_|I94Z19BEPEicMdPx57;M0>A_LlN)5<5; zzltv>glZD)+iEX8CBfax!2fk1Ke=mp2^R-6A$&71GmZIw)d0{`)lsQXwh8|qT!6zT literal 0 HcmV?d00001 diff --git a/contracts/icons/token.svg b/contracts/icons/token.svg new file mode 100644 index 000000000..67ff415ba --- /dev/null +++ b/contracts/icons/token.svg @@ -0,0 +1 @@ +Token_1 \ No newline at end of file diff --git a/contracts/icons/transfer.png b/contracts/icons/transfer.png new file mode 100644 index 0000000000000000000000000000000000000000..d9c021957516ff0e1873a54feb4f40f547c62bed GIT binary patch literal 3856 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 C9O3i; literal 0 HcmV?d00001 diff --git a/contracts/icons/transfer.svg b/contracts/icons/transfer.svg new file mode 100644 index 000000000..06da6325c --- /dev/null +++ b/contracts/icons/transfer.svg @@ -0,0 +1 @@ +Transfer_1 \ No newline at end of file diff --git a/contracts/icons/voting.png b/contracts/icons/voting.png new file mode 100644 index 0000000000000000000000000000000000000000..0356bddaf2b0f61f82f8dbd7cfad977e0757b187 GIT binary patch literal 3238 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 Z0VhTSOesfxtUm={pRKdagFTE({{svY!SDb8 literal 0 HcmV?d00001 diff --git a/contracts/icons/voting.svg b/contracts/icons/voting.svg new file mode 100644 index 000000000..fac870898 --- /dev/null +++ b/contracts/icons/voting.svg @@ -0,0 +1 @@ +Voting_1 \ No newline at end of file From 36817c3db8dd852a1c2f11e5073973be4fcb5983 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 20:13:06 -0400 Subject: [PATCH 019/106] remove unnecessary EOSIO_DISPATCH macros; add action wrappers for activate and reqactivated actions --- .../include/eosio.bios/eosio.bios.hpp | 82 ++++++------------- contracts/eosio.bios/src/eosio.bios.cpp | 58 ++++++++++++- contracts/eosio.msig/src/eosio.msig.cpp | 2 - .../include/eosio.system/eosio.system.hpp | 16 +--- contracts/eosio.system/src/eosio.system.cpp | 18 ---- contracts/eosio.token/src/eosio.token.cpp | 2 - contracts/eosio.wrap/src/eosio.wrap.cpp | 2 - 7 files changed, 81 insertions(+), 99 deletions(-) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 80e6faae9..637e2bebe 100755 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -289,6 +289,19 @@ namespace eosio { /** @}*/ + /** + * Set abi for contract. + * + * @details Set 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. + * + * @param account - the name of the account to set the abi for + * @param abi - the abi hash represented as a vector of characters + */ + [[eosio::action]] + void setabi( name account, const std::vector& abi ); + /** * Set privilege status for an account. * @@ -297,10 +310,7 @@ namespace eosio { * @param is_priv - 0 for false, > 0 for true. */ [[eosio::action]] - void setpriv( name account, uint8_t is_priv ) { - require_auth( _self ); - set_privileged( account.value, is_priv ); - } + void setpriv( name account, uint8_t is_priv ); /** * Set the resource limits of an account @@ -313,10 +323,7 @@ namespace eosio { * @param cpu_weight - fractionally proportionate cpu limit of available resources based on (weight / total_weight_of_all_accounts) */ [[eosio::action]] - void setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) { - require_auth( _self ); - set_resource_limits( account.value, ram_bytes, net_weight, cpu_weight ); - } + 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. @@ -329,16 +336,7 @@ namespace eosio { * @param schedule - New list of active producers to set */ [[eosio::action]] - void setprods( std::vector schedule ) { - (void)schedule; // schedule argument just forces the deserialization of the action data into vector (necessary check) - require_auth( _self ); - - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - set_proposed_producers(buffer, size); - } + void setprods( std::vector schedule ); /** * Set the blockchain parameters @@ -348,10 +346,7 @@ namespace eosio { * @param params - New blockchain parameters to set */ [[eosio::action]] - void setparams( const eosio::blockchain_parameters& params ) { - require_auth( _self ); - set_blockchain_parameters( params ); - } + void setparams( const eosio::blockchain_parameters& params ); /** * Check if an account has authorization to access current action. @@ -362,9 +357,7 @@ namespace eosio { * @param from - the account name to authorize */ [[eosio::action]] - void reqauth( name from ) { - require_auth( from ); - } + void reqauth( name from ); /** * Activates a protocol feature. @@ -374,10 +367,7 @@ namespace eosio { * @param feature_digest - hash of the protocol feature to activate. */ [[eosio::action]] - void activate( const eosio::checksum256& feature_digest ) { - require_auth( get_self() ); - preactivate_feature( feature_digest ); - } + void activate( const eosio::checksum256& feature_digest ); /** * Asserts that a protocol feature has been activated. @@ -387,35 +377,7 @@ namespace eosio { * @param feature_digest - hash of the protocol feature to check for activation. */ [[eosio::action]] - void reqactivated( const eosio::checksum256& feature_digest ) { - check( is_feature_activated( feature_digest ), "protocol feature is not activated" ); - } - - /** - * Set abi for contract. - * - * @details Set 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. - * - * @param account - the name of the account to set the abi for - * @param abi - the abi hash represented as a vector of characters - */ - [[eosio::action]] - void setabi( name account, const std::vector& abi ) { - abi_hash_table table(_self, _self.value); - auto itr = table.find( account.value ); - if( itr == table.end() ) { - table.emplace( account, [&]( auto& row ) { - row.owner = account; - sha256( const_cast(abi.data()), abi.size(), &row.hash ); - }); - } else { - table.modify( itr, same_payer, [&]( auto& row ) { - sha256( const_cast(abi.data()), abi.size(), &row.hash ); - }); - } - } + void reqactivated( const eosio::checksum256& feature_digest ); /** * Abi hash structure @@ -442,12 +404,14 @@ namespace eosio { using unlinkauth_action = action_wrapper<"unlinkauth"_n, &bios::unlinkauth>; using canceldelay_action = action_wrapper<"canceldelay"_n, &bios::canceldelay>; using setcode_action = action_wrapper<"setcode"_n, &bios::setcode>; + using setabi_action = action_wrapper<"setabi"_n, &bios::setabi>; 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 setparams_action = action_wrapper<"setparams"_n, &bios::setparams>; using reqauth_action = action_wrapper<"reqauth"_n, &bios::reqauth>; - using setabi_action = action_wrapper<"setabi"_n, &bios::setabi>; + 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 eosio diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index 9a080e5e4..f62809843 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -1,3 +1,59 @@ #include -EOSIO_DISPATCH( eosio::bios, (setpriv)(setalimits)(setprods)(setparams)(reqauth)(setabi)(activate)(reqactivated) ) +namespace eosio { + +void bios::setabi( name account, const std::vector& abi ) { + abi_hash_table table(_self, _self.value); + auto itr = table.find( account.value ); + if( itr == table.end() ) { + table.emplace( account, [&]( auto& row ) { + row.owner = account; + sha256( const_cast(abi.data()), abi.size(), &row.hash ); + }); + } else { + table.modify( itr, same_payer, [&]( auto& row ) { + sha256( const_cast(abi.data()), abi.size(), &row.hash ); + }); + } +} + +void bios::setpriv( name account, uint8_t is_priv ) { + require_auth( _self ); + set_privileged( account.value, is_priv ); +} + +void bios::setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) { + require_auth( _self ); + set_resource_limits( account.value, ram_bytes, net_weight, cpu_weight ); +} + +void bios::setprods( std::vector schedule ) { + (void)schedule; // schedule argument just forces the deserialization of the action data into vector (necessary check) + require_auth( _self ); + + constexpr size_t max_stack_buffer_size = 512; + size_t size = action_data_size(); + char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); + read_action_data( buffer, size ); + set_proposed_producers(buffer, size); +} + +void bios::setparams( const eosio::blockchain_parameters& params ) { + require_auth( _self ); + set_blockchain_parameters( params ); +} + +void bios::reqauth( name from ) { + require_auth( from ); +} + +void bios::activate( const eosio::checksum256& feature_digest ) { + require_auth( get_self() ); + preactivate_feature( feature_digest ); +} + +void bios::reqactivated( const eosio::checksum256& feature_digest ) { + check( is_feature_activated( feature_digest ), "protocol feature is not activated" ); +} + +} diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index 1a9ca4e06..741bcbd8d 100755 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -213,5 +213,3 @@ void multisig::invalidate( name account ) { } } /// namespace eosio - -EOSIO_DISPATCH( eosio::multisig, (propose)(approve)(unapprove)(cancel)(exec)(invalidate) ) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 14c2f383d..6e287c465 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1167,6 +1167,7 @@ namespace eosiosystem { using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; using setacctnet_action = eosio::action_wrapper<"setacctnet"_n, &system_contract::setacctnet>; using setacctcpu_action = eosio::action_wrapper<"setacctcpu"_n, &system_contract::setacctcpu>; + using activate_action = eosio::action_wrapper<"activate"_n, &system_contract::activate>; using delegatebw_action = eosio::action_wrapper<"delegatebw"_n, &system_contract::delegatebw>; using deposit_action = eosio::action_wrapper<"deposit"_n, &system_contract::deposit>; using withdraw_action = eosio::action_wrapper<"withdraw"_n, &system_contract::withdraw>; @@ -1183,21 +1184,7 @@ namespace eosiosystem { using updaterex_action = eosio::action_wrapper<"updaterex"_n, &system_contract::updaterex>; using rexexec_action = eosio::action_wrapper<"rexexec"_n, &system_contract::rexexec>; using setrex_action = eosio::action_wrapper<"setrex"_n, &system_contract::setrex>; - /** - * Move to savings action. - * - * @details Moves a specified amount of REX to savings bucket. - * @param owner - account name of REX owner - * @param rex - amount of REX to be moved - */ using mvtosavings_action = eosio::action_wrapper<"mvtosavings"_n, &system_contract::mvtosavings>; - /** - * Move from savings action. - * - * @details Moves a specified amount of REX from savings bucket - * @param owner - account name of REX owner - * @param rex - amount of REX to be moved - */ using mvfrsavings_action = eosio::action_wrapper<"mvfrsavings"_n, &system_contract::mvfrsavings>; using consolidate_action = eosio::action_wrapper<"consolidate"_n, &system_contract::consolidate>; using closerex_action = eosio::action_wrapper<"closerex"_n, &system_contract::closerex>; @@ -1213,7 +1200,6 @@ namespace eosiosystem { using voteproducer_action = eosio::action_wrapper<"voteproducer"_n, &system_contract::voteproducer>; using regproxy_action = eosio::action_wrapper<"regproxy"_n, &system_contract::regproxy>; using claimrewards_action = eosio::action_wrapper<"claimrewards"_n, &system_contract::claimrewards>; - using rmvproducer_action = eosio::action_wrapper<"rmvproducer"_n, &system_contract::rmvproducer>; using updtrevision_action = eosio::action_wrapper<"updtrevision"_n, &system_contract::updtrevision>; using bidname_action = eosio::action_wrapper<"bidname"_n, &system_contract::bidname>; diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index 1eec7c1ad..bdccb51ee 100755 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -450,21 +450,3 @@ namespace eosiosystem { } } /// eosio.system - - -EOSIO_DISPATCH( eosiosystem::system_contract, - // native.hpp (newaccount definition is actually in eosio.system.cpp) - (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)(setabi) - // eosio.system.cpp - (init)(setram)(setramrate)(setparams)(setpriv)(setalimits)(setacctram)(setacctnet)(setacctcpu)(activate) - (rmvproducer)(updtrevision)(bidname)(bidrefund) - // rex.cpp - (deposit)(withdraw)(buyrex)(unstaketorex)(sellrex)(cnclrexorder)(rentcpu)(rentnet)(fundcpuloan)(fundnetloan) - (defcpuloan)(defnetloan)(updaterex)(consolidate)(mvtosavings)(mvfrsavings)(setrex)(rexexec)(closerex) - // delegate_bandwidth.cpp - (buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund) - // voting.cpp - (regproducer)(unregprod)(voteproducer)(regproxy) - // producer_pay.cpp - (onblock)(claimrewards) -) diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index 9d246d4b6..a0b5ad631 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -156,5 +156,3 @@ void token::close( const name& owner, const symbol& symbol ) } } /// namespace eosio - -EOSIO_DISPATCH( eosio::token, (create)(issue)(transfer)(open)(close)(retire) ) diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index d8a034466..89f92e593 100755 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -14,5 +14,3 @@ void wrap::exec( ignore, ignore ) { } } /// namespace eosio - -EOSIO_DISPATCH( eosio::wrap, (exec) ) From f280bea94b84ad87789d819f889f535eeda53ce9 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 20 Jun 2019 20:38:10 -0400 Subject: [PATCH 020/106] disallow directly calling onerror action --- .../include/eosio.bios/eosio.bios.hpp | 24 ++++++++++--------- contracts/eosio.bios/src/eosio.bios.cpp | 4 ++++ .../include/eosio.system/native.hpp | 12 ++++++---- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 637e2bebe..96cdfe3c1 100755 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -263,17 +263,6 @@ namespace eosio { [[eosio::action]] void canceldelay( ignore canceling_auth, ignore trx_id ) {} - /** - * On error action. - * - * @details Called every time an error occurs while a transaction was processed. - * - * @param sender_id - the id of the sender, - * @param sent_trx - the transaction that failed. - */ - [[eosio::action]] - void onerror( ignore sender_id, ignore> sent_trx ) {} - /** * Set code action. * @@ -302,6 +291,19 @@ namespace eosio { [[eosio::action]] 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 + * when an objective error occurs while executing the deferred transaction. + * This action is not meant to be called directly. + * + * @param sender_id - the id for the deferred transaction chosen by the sender, + * @param sent_trx - the deferred transaction that failed. + */ + [[eosio::action]] + void onerror( ignore sender_id, ignore> sent_trx ); + /** * Set privilege status for an account. * diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index f62809843..c40a3a3c4 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -17,6 +17,10 @@ void bios::setabi( name account, const std::vector& abi ) { } } +void bios::onerror( ignore, ignore> ) { + check( false, "the onerror action cannot be called directly" ); +} + void bios::setpriv( name account, uint8_t is_priv ) { require_auth( _self ); set_privileged( account.value, is_priv ); diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index e197485b1..09c3bfc3b 100755 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -267,13 +267,17 @@ namespace eosiosystem { /** * On error action. * - * @details Called every time an error occurs while a transaction was processed. + * @details 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. * - * @param sender_id - the id of the sender, - * @param sent_trx - the transaction that failed. + * @param sender_id - the id for the deferred transaction chosen by the sender, + * @param sent_trx - the deferred transaction that failed. */ [[eosio::action]] - void onerror( ignore sender_id, ignore> sent_trx ) {} + void onerror( ignore sender_id, ignore> sent_trx ) { + eosio::check( false, "the onerror action cannot be called directly" ); + } /** * Set abi action. From 05892c0d7b531246d8eef8f23996d35c25da77cb Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 25 Jun 2019 11:13:36 -0400 Subject: [PATCH 021/106] update eosio.bios contract to work with new CDT v1.6.x headers --- .../include/eosio.bios/eosio.bios.hpp | 28 +++++++++++-------- contracts/eosio.bios/src/eosio.bios.cpp | 16 ++++------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 96cdfe3c1..763b9bb53 100755 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -1,10 +1,14 @@ #pragma once -#include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include +#include + +// This header is needed until `is_feature_activated` and `preactivate_feature` are added to `eosio.cdt` +#include namespace eosio { namespace internal_use_do_not_use { @@ -55,9 +59,9 @@ namespace eosio { namespace eosio { + using eosio::ignore; using eosio::permission_level; using eosio::public_key; - using eosio::ignore; /** * A weighted permission. @@ -137,9 +141,9 @@ namespace eosio { uint32_t timestamp; name producer; uint16_t confirmed = 0; - capi_checksum256 previous; - capi_checksum256 transaction_mroot; - capi_checksum256 action_mroot; + checksum256 previous; + checksum256 transaction_mroot; + checksum256 action_mroot; uint32_t schedule_version = 0; std::optional new_producers; @@ -261,7 +265,7 @@ namespace eosio { * @param trx_id - the deferred transaction id to be cancelled. */ [[eosio::action]] - void canceldelay( ignore canceling_auth, ignore trx_id ) {} + void canceldelay( ignore canceling_auth, ignore trx_id ) {} /** * Set code action. @@ -388,7 +392,7 @@ namespace eosio { */ struct [[eosio::table]] abi_hash { name owner; - capi_checksum256 hash; + checksum256 hash; uint64_t primary_key()const { return owner.value; } EOSLIB_SERIALIZE( abi_hash, (owner)(hash) ) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index c40a3a3c4..d652ed114 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -8,11 +8,11 @@ void bios::setabi( name account, const std::vector& abi ) { if( itr == table.end() ) { table.emplace( account, [&]( auto& row ) { row.owner = account; - sha256( const_cast(abi.data()), abi.size(), &row.hash ); + row.hash = sha256(const_cast(abi.data()), abi.size()); }); } else { table.modify( itr, same_payer, [&]( auto& row ) { - sha256( const_cast(abi.data()), abi.size(), &row.hash ); + row.hash = sha256(const_cast(abi.data()), abi.size()); }); } } @@ -23,23 +23,17 @@ void bios::onerror( ignore, ignore> ) { void bios::setpriv( name account, uint8_t is_priv ) { require_auth( _self ); - set_privileged( account.value, is_priv ); + set_privileged( account, is_priv ); } void bios::setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) { require_auth( _self ); - set_resource_limits( account.value, ram_bytes, net_weight, cpu_weight ); + set_resource_limits( account, ram_bytes, net_weight, cpu_weight ); } void bios::setprods( std::vector schedule ) { - (void)schedule; // schedule argument just forces the deserialization of the action data into vector (necessary check) require_auth( _self ); - - constexpr size_t max_stack_buffer_size = 512; - size_t size = action_data_size(); - char* buffer = (char*)( max_stack_buffer_size < size ? malloc(size) : alloca(size) ); - read_action_data( buffer, size ); - set_proposed_producers(buffer, size); + set_proposed_producers( schedule ); } void bios::setparams( const eosio::blockchain_parameters& params ) { From 2b0b2dd99e4df5bacfbf757bd0c2d4a02f469b11 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 25 Jun 2019 11:41:14 -0400 Subject: [PATCH 022/106] update eosio.msig contract to work with new CDT v1.6.x headers; also workaround check_transaction_authorization bug --- .../include/eosio.msig/eosio.msig.hpp | 77 ++++++++++--------- contracts/eosio.msig/src/eosio.msig.cpp | 42 ++++------ 2 files changed, 57 insertions(+), 62 deletions(-) diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index bb22cea00..cd9237349 100755 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -1,7 +1,9 @@ #pragma once -#include -#include -#include + +#include +#include +#include +#include namespace eosio { /** @@ -16,18 +18,18 @@ namespace eosio { /** * Create proposal - * + * * @details Creates a proposal containing one transaction. * Allows an account `proposer` to make a proposal `proposal_name` which has `requested` - * permission levels expected to approve the proposal, and if approved by all expected + * permission levels expected to approve the proposal, and if approved by all expected * permission levels then `trx` transaction can we executed by this proposal. - * The `proposer` account is authorized and the `trx` transaction is verified if it was - * authorized by the provided keys and permissions, and if the proposal name doesn’t - * already exist; if all validations pass the `proposal_name` and `trx` trasanction are - * saved in the proposals table and the `requested` permission levels to the + * The `proposer` account is authorized and the `trx` transaction is verified if it was + * authorized by the provided keys and permissions, and if the proposal name doesn’t + * already exist; if all validations pass the `proposal_name` and `trx` trasanction are + * saved in the proposals table and the `requested` permission levels to the * approvals table (for the `proposer` context). * Storage changes are billed to `proposer`. - * + * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be unique for proposer) * @param requested - Permission levels expected to approve the proposal @@ -38,15 +40,15 @@ namespace eosio { ignore> requested, ignore trx); /** * Approve proposal - * + * * @details Approves an existing proposal * Allows an account, the owner of `level` permission, to approve a proposal `proposal_name` - * proposed by `proposer`. If the proposal's requested approval list contains the `level` - * permission then the `level` permission is moved from internal `requested_approvals` list to - * internal `provided_approvals` list of the proposal, thus persisting the approval for + * proposed by `proposer`. If the proposal's requested approval list contains the `level` + * permission then the `level` permission is moved from internal `requested_approvals` list to + * internal `provided_approvals` list of the proposal, thus persisting the approval for * the `proposal_name` proposal. * Storage changes are billed to `proposer`. - * + * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be unique for proposer) * @param level - Permission level approving the transaction @@ -57,12 +59,12 @@ namespace eosio { const eosio::binary_extension& proposal_hash ); /** * Revoke proposal - * + * * @details Revokes an existing proposal - * This action is the reverse of the `approve` action: if all validations pass - * the `level` permission is erased from internal `provided_approvals` and added to the internal + * This action is the reverse of the `approve` action: if all validations pass + * the `level` permission is erased from internal `provided_approvals` and added to the internal * `requested_approvals` list, and thus un-approve or revoke the proposal. - * + * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be an existing proposal) * @param level - Permission level revoking approval for proposal @@ -71,34 +73,34 @@ namespace eosio { void unapprove( name proposer, name proposal_name, permission_level level ); /** * Cancel proposal - * + * * @details Cancels an existing proposal - * + * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be an existing proposal) * @param canceler - The account cancelling the proposal (only the proposer can cancel an unexpired transaction, and the canceler has to be different than the proposer) - * - * Allows the `canceler` account to cancel the `proposal_name` proposal, created by a `proposer`, - * only after time has expired on the proposed transaction. It removes corresponding entries from + * + * Allows the `canceler` account to cancel the `proposal_name` proposal, created by a `proposer`, + * only after time has expired on the proposed transaction. It removes corresponding entries from * internal proptable and from approval (or old approvals) tables as well. */ [[eosio::action]] void cancel( name proposer, name proposal_name, name canceler ); /** * Execute proposal - * + * * @details Allows an `executer` account to execute a proposal. - * - * Preconditions: - * - `executer` has authorization, - * - `proposal_name` is found in the proposals table, - * - all requested approvals are received, - * - proposed transaction is not expired, - * - and approval accounts are not found in invalidations table. - * + * + * Preconditions: + * - `executer` has authorization, + * - `proposal_name` is found in the proposals table, + * - all requested approvals are received, + * - proposed transaction is not expired, + * - and approval accounts are not found in invalidations table. + * * If all preconditions are met the transaction is executed as a deferred transaction, * and the proposal is erased from the proposals table. - * + * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be an existing proposal) * @param executer - The account executing the transaction @@ -107,10 +109,10 @@ namespace eosio { void exec( name proposer, name proposal_name, name executer ); /** * Invalidate proposal - * - * @details Allows an `account` to invalidate itself, that is, its name is added to + * + * @details Allows an `account` to invalidate itself, that is, its name is added to * the invalidations table and this table will be cross referenced when exec is performed. - * + * * @param account - The account invalidating the transaction */ [[eosio::action]] @@ -122,6 +124,7 @@ namespace eosio { using cancel_action = eosio::action_wrapper<"cancel"_n, &multisig::cancel>; using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>; using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>; + private: struct [[eosio::table]] proposal { name proposal_name; diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index 741bcbd8d..a410e13a3 100755 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -1,22 +1,10 @@ #include -#include -#include -#include -namespace eosio { +#include +#include +#include -/** - * @ingroup eosiocontracts - * - * Returns a high resolution time_point - * - * @details Returns a high resolution time_point which represents the number of microseconds - * from 1970 until the current time. - */ -time_point current_time_point() { - const static time_point ct{ microseconds{ static_cast( current_time() ) } }; - return ct; -} +namespace eosio { void multisig::propose( ignore proposer, ignore proposal_name, @@ -42,10 +30,12 @@ void multisig::propose( ignore proposer, check( proptable.find( _proposal_name.value ) == proptable.end(), "proposal with the same name exists" ); auto packed_requested = pack(_requested); - auto res = ::check_transaction_authorization( trx_pos, size, - (const char*)0, 0, - packed_requested.data(), packed_requested.size() - ); + // TODO: Remove internal_use_do_not_use namespace after minimum eosio.cdt dependency becomes 1.7.x + auto res = internal_use_do_not_use::check_transaction_authorization( + trx_pos, size, + (const char*)0, 0, + packed_requested.data(), packed_requested.size() + ); check( res > 0, "transaction authorization failed" ); std::vector pkd_trans; @@ -184,13 +174,15 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { old_apptable.erase(apps); } auto packed_provided_approvals = pack(approvals); - auto res = ::check_transaction_authorization( prop.packed_transaction.data(), prop.packed_transaction.size(), - (const char*)0, 0, - packed_provided_approvals.data(), packed_provided_approvals.size() - ); + // TODO: Remove internal_use_do_not_use namespace after minimum eosio.cdt dependency becomes 1.7.x + auto res = internal_use_do_not_use::check_transaction_authorization( + prop.packed_transaction.data(), prop.packed_transaction.size(), + (const char*)0, 0, + packed_provided_approvals.data(), packed_provided_approvals.size() + ); check( res > 0, "transaction authorization failed" ); - send_deferred( (uint128_t(proposer.value) << 64) | proposal_name.value, executer.value, + send_deferred( (uint128_t(proposer.value) << 64) | proposal_name.value, executer, prop.packed_transaction.data(), prop.packed_transaction.size() ); proptable.erase(prop); From 13f6fd664d41fbbe83853c6aef14b12f82b7476d Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 25 Jun 2019 14:45:14 -0400 Subject: [PATCH 023/106] update eosio.system, eosio.token, and eosio.wrap contracts to work with new CDT v1.6.x headers --- .../include/eosio.system/eosio.system.hpp | 34 +++++++------- .../include/eosio.system/exchange_state.hpp | 7 +-- .../include/eosio.system/native.hpp | 39 +++++++++------- .../include/eosio.system/rex.results.hpp | 10 ++--- .../eosio.system/src/delegate_bandwidth.cpp | 34 +++++++------- contracts/eosio.system/src/eosio.system.cpp | 44 +++++++------------ contracts/eosio.system/src/producer_pay.cpp | 1 - contracts/eosio.system/src/rex.cpp | 8 ++-- contracts/eosio.system/src/voting.cpp | 29 ++++++------ .../include/eosio.token/eosio.token.hpp | 4 +- .../include/eosio.wrap/eosio.wrap.hpp | 22 +++++----- contracts/eosio.wrap/src/eosio.wrap.cpp | 3 +- 12 files changed, 114 insertions(+), 121 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6e287c465..e5657f77d 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1,16 +1,19 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + #include +#include -#include #include -#include #include +#include +#include + #ifdef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX #undef CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX @@ -22,18 +25,20 @@ namespace eosiosystem { - using eosio::name; using eosio::asset; + using eosio::block_timestamp; + using eosio::check; + using eosio::const_mem_fun; + using eosio::datastream; + using eosio::indexed_by; + using eosio::microseconds; + using eosio::name; using eosio::symbol; using eosio::symbol_code; - using eosio::indexed_by; - using eosio::const_mem_fun; - using eosio::block_timestamp; using eosio::time_point; using eosio::time_point_sec; using eosio::microseconds; - using eosio::datastream; - using eosio::check; + using eosio::unsigned_int; template static inline auto has_field( F flags, E field ) @@ -1219,9 +1224,6 @@ namespace eosiosystem { //defined in eosio.system.cpp static eosio_global_state get_default_parameters(); - static time_point current_time_point(); - static time_point_sec current_time_point_sec(); - static block_timestamp current_block_time(); symbol core_symbol()const; void update_ram_supply(); diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 04119895a..15988e04a 100755 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -1,8 +1,9 @@ #pragma once -#include +#include namespace eosiosystem { + using eosio::asset; using eosio::symbol; @@ -13,8 +14,8 @@ namespace eosiosystem { /** * Uses Bancor math to create a 50/50 relay between two asset types. - * - * @details The state of the bancor exchange is entirely contained within this struct. + * + * @details The state of the bancor exchange is entirely contained within this struct. * There are no external side effects associated with using this API. */ struct [[eosio::table, eosio::contract("eosio.system")]] exchange_state { diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index 09c3bfc3b..6ae7a6c7a 100755 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -1,13 +1,16 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +// This header is needed until `is_feature_activiated` and `preactivate_feature` are added to `eosio.cdt` +#include namespace eosio { namespace internal_use_do_not_use { @@ -15,13 +18,13 @@ namespace eosio { __attribute__((eosio_wasm_import)) bool is_feature_activated( const ::capi_checksum256* feature_digest ); - __attribute__((eosio_wasm_import)) + __attribute__((eosio_wasm_import)) void preactivate_feature( const ::capi_checksum256* feature_digest ); } } } - namespace eosio { +namespace eosio { bool is_feature_activated( const eosio::checksum256& feature_digest ) { auto feature_digest_data = feature_digest.extract_as_byte_array(); return internal_use_do_not_use::is_feature_activated( @@ -29,7 +32,7 @@ namespace eosio { ); } - void preactivate_feature( const eosio::checksum256& feature_digest ) { + void preactivate_feature( const eosio::checksum256& feature_digest ) { auto feature_digest_data = feature_digest.extract_as_byte_array(); internal_use_do_not_use::preactivate_feature( reinterpret_cast( feature_digest_data.data() ) @@ -38,10 +41,12 @@ namespace eosio { } namespace eosiosystem { + + using eosio::checksum256; + using eosio::ignore; using eosio::name; using eosio::permission_level; using eosio::public_key; - using eosio::ignore; /** * @addtogroup eosiosystem @@ -123,9 +128,9 @@ namespace eosiosystem { uint32_t timestamp; name producer; uint16_t confirmed = 0; - capi_checksum256 previous; - capi_checksum256 transaction_mroot; - capi_checksum256 action_mroot; + checksum256 previous; + checksum256 transaction_mroot; + checksum256 action_mroot; uint32_t schedule_version = 0; std::optional new_producers; @@ -143,7 +148,7 @@ namespace eosiosystem { */ struct [[eosio::table("abihash"), eosio::contract("eosio.system")]] abi_hash { name owner; - capi_checksum256 hash; + checksum256 hash; uint64_t primary_key()const { return owner.value; } EOSLIB_SERIALIZE( abi_hash, (owner)(hash) ) @@ -262,7 +267,7 @@ namespace eosiosystem { * @param trx_id - the deferred transaction id to be cancelled. */ [[eosio::action]] - void canceldelay( ignore canceling_auth, ignore trx_id ) {} + void canceldelay( ignore canceling_auth, ignore trx_id ) {} /** * On error action. diff --git a/contracts/eosio.system/include/eosio.system/rex.results.hpp b/contracts/eosio.system/include/eosio.system/rex.results.hpp index d1ba0fb00..b5a1949c9 100644 --- a/contracts/eosio.system/include/eosio.system/rex.results.hpp +++ b/contracts/eosio.system/include/eosio.system/rex.results.hpp @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include +#include +#include +#include -using eosio::name; -using eosio::asset; using eosio::action_wrapper; +using eosio::asset; +using eosio::name; class [[eosio::contract("rex.results")]] rex_results : eosio::contract { public: diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 16ea90da9..71fb2169d 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -1,24 +1,24 @@ -#include - -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include - #include #include namespace eosiosystem { + using eosio::asset; - using eosio::indexed_by; using eosio::const_mem_fun; + using eosio::indexed_by; using eosio::permission_level; using eosio::time_point_sec; + using std::map; using std::pair; @@ -157,8 +157,8 @@ namespace eosiosystem { auto voter_itr = _voters.find( res_itr->owner.value ); if( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { int64_t ram_bytes, net, cpu; - get_resource_limits( res_itr->owner.value, &ram_bytes, &net, &cpu ); - set_resource_limits( res_itr->owner.value, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); + get_resource_limits( res_itr->owner, ram_bytes, net, cpu ); + set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); } } @@ -201,8 +201,8 @@ namespace eosiosystem { auto voter_itr = _voters.find( res_itr->owner.value ); if( voter_itr == _voters.end() || !has_field( voter_itr->flags1, voter_info::flags1_fields::ram_managed ) ) { int64_t ram_bytes, net, cpu; - get_resource_limits( res_itr->owner.value, &ram_bytes, &net, &cpu ); - set_resource_limits( res_itr->owner.value, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); + get_resource_limits( res_itr->owner, ram_bytes, net, cpu ); + set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu ); } { @@ -221,7 +221,7 @@ namespace eosiosystem { void validate_b1_vesting( int64_t stake ) { const int64_t base_time = 1527811200; /// 2018-06-01 const int64_t max_claimable = 100'000'000'0000ll; - const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); + const int64_t claimable = int64_t(max_claimable * double(current_time_point().sec_since_epoch() - base_time) / (10*seconds_per_year) ); check( max_claimable - claimable <= stake, "b1 can only claim their tokens over 10 years" ); } @@ -298,9 +298,9 @@ namespace eosiosystem { if( !(net_managed && cpu_managed) ) { int64_t ram_bytes, net, cpu; - get_resource_limits( receiver.value, &ram_bytes, &net, &cpu ); + get_resource_limits( receiver, ram_bytes, net, cpu ); - set_resource_limits( receiver.value, + set_resource_limits( receiver, ram_managed ? ram_bytes : std::max( tot_itr->ram_bytes + ram_gift_bytes, ram_bytes ), net_managed ? net : tot_itr->net_weight.amount, cpu_managed ? cpu : tot_itr->cpu_weight.amount ); diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index bdccb51ee..b80868abc 100755 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -1,6 +1,7 @@ +#include +#include + #include -#include -#include #include "producer_pay.cpp" #include "delegate_bandwidth.cpp" @@ -36,21 +37,6 @@ namespace eosiosystem { return dp; } - time_point system_contract::current_time_point() { - const static time_point ct{ microseconds{ static_cast( current_time() ) } }; - return ct; - } - - time_point_sec system_contract::current_time_point_sec() { - const static time_point_sec cts{ current_time_point() }; - return cts; - } - - block_timestamp system_contract::current_block_time() { - const static block_timestamp cbt{ current_time_point() }; - return cbt; - } - symbol system_contract::core_symbol()const { const static auto sym = get_core_symbol( _rammarket ); return sym; @@ -116,7 +102,7 @@ namespace eosiosystem { void system_contract::setpriv( const name& account, uint8_t ispriv ) { require_auth( _self ); - set_privileged( account.value, ispriv ); + set_privileged( account, ispriv ); } void system_contract::setalimits( const name& account, int64_t ram, int64_t net, int64_t cpu ) { @@ -134,14 +120,14 @@ namespace eosiosystem { check( !(ram_managed || net_managed || cpu_managed), "cannot use setalimits on an account with managed resources" ); } - set_resource_limits( account.value, ram, net, cpu ); + set_resource_limits( account, ram, net, cpu ); } void system_contract::setacctram( const name& account, const std::optional& ram_bytes ) { require_auth( _self ); int64_t current_ram, current_net, current_cpu; - get_resource_limits( account.value, ¤t_ram, ¤t_net, ¤t_cpu ); + get_resource_limits( account, current_ram, current_net, current_cpu ); int64_t ram = 0; @@ -179,14 +165,14 @@ namespace eosiosystem { ram = *ram_bytes; } - set_resource_limits( account.value, ram, current_net, current_cpu ); + set_resource_limits( account, ram, current_net, current_cpu ); } void system_contract::setacctnet( const name& account, const std::optional& net_weight ) { require_auth( _self ); int64_t current_ram, current_net, current_cpu; - get_resource_limits( account.value, ¤t_ram, ¤t_net, ¤t_cpu ); + get_resource_limits( account, current_ram, current_net, current_cpu ); int64_t net = 0; @@ -223,14 +209,14 @@ namespace eosiosystem { net = *net_weight; } - set_resource_limits( account.value, current_ram, net, current_cpu ); + set_resource_limits( account, current_ram, net, current_cpu ); } void system_contract::setacctcpu( const name& account, const std::optional& cpu_weight ) { require_auth( _self ); int64_t current_ram, current_net, current_cpu; - get_resource_limits( account.value, ¤t_ram, ¤t_net, ¤t_cpu ); + get_resource_limits( account, current_ram, current_net, current_cpu ); int64_t cpu = 0; @@ -267,7 +253,7 @@ namespace eosiosystem { cpu = *cpu_weight; } - set_resource_limits( account.value, current_ram, current_net, cpu ); + set_resource_limits( account, current_ram, current_net, cpu ); } void system_contract::activate( const eosio::checksum256& feature_digest ) { @@ -407,7 +393,7 @@ namespace eosiosystem { res.cpu_weight = asset( 0, system_contract::get_core_symbol() ); }); - set_resource_limits( newact.value, 0, 0, 0 ); + set_resource_limits( newact, 0, 0, 0 ); } void native::setabi( const name& acnt, const std::vector& abi ) { @@ -415,12 +401,12 @@ namespace eosiosystem { auto itr = table.find( acnt.value ); if( itr == table.end() ) { table.emplace( acnt, [&]( auto& row ) { - row.owner= acnt; - sha256( const_cast(abi.data()), abi.size(), &row.hash ); + row.owner = acnt; + row.hash = sha256(const_cast(abi.data()), abi.size()); }); } else { table.modify( itr, same_payer, [&]( auto& row ) { - sha256( const_cast(abi.data()), abi.size(), &row.hash ); + row.hash = sha256(const_cast(abi.data()), abi.size()); }); } } diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index f2fc03035..67d0d99a5 100755 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -1,5 +1,4 @@ #include - #include namespace eosiosystem { diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 125ae6579..8e737532b 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -392,9 +392,9 @@ namespace eosiosystem { if( !(net_managed && cpu_managed) ) { int64_t ram_bytes = 0, net = 0, cpu = 0; - get_resource_limits( receiver.value, &ram_bytes, &net, &cpu ); + get_resource_limits( receiver, ram_bytes, net, cpu ); - set_resource_limits( receiver.value, + set_resource_limits( receiver, ram_bytes, net_managed ? net : tot_itr->net_weight.amount, cpu_managed ? cpu : tot_itr->cpu_weight.amount ); @@ -851,7 +851,7 @@ namespace eosiosystem { time_point_sec system_contract::get_rex_maturity() { const uint32_t num_of_maturity_buckets = 5; - static const uint32_t now = current_time_point_sec().utc_seconds; + static const uint32_t now = current_time_point().sec_since_epoch(); static const uint32_t r = now % seconds_per_day; static const time_point_sec rms{ now - r + num_of_maturity_buckets * seconds_per_day }; return rms; @@ -864,7 +864,7 @@ namespace eosiosystem { */ void system_contract::process_rex_maturities( const rex_balance_table::const_iterator& bitr ) { - const time_point_sec now = current_time_point_sec(); + const time_point_sec now = current_time_point(); _rexbalance.modify( bitr, same_payer, [&]( auto& rb ) { while ( !rb.rex_maturities.empty() && rb.rex_maturities.front().first <= now ) { rb.matured_rex += rb.rex_maturities.front().second; diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index c5b89672c..cc540297d 100755 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -1,21 +1,22 @@ -#include +#include +#include +#include +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include namespace eosiosystem { - using eosio::indexed_by; + using eosio::const_mem_fun; + using eosio::indexed_by; using eosio::singleton; using eosio::transaction; @@ -98,16 +99,14 @@ namespace eosiosystem { for( const auto& item : top_producers ) producers.push_back(item.first); - auto packed_schedule = pack(producers); - - if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { + if( set_proposed_producers( producers ) >= 0 ) { _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); } } double stake2vote( int64_t staked ) { /// TODO subtract 2080 brings the large numbers closer to this decade - double weight = int64_t( (now() - (block_timestamp::block_timestamp_epoch / 1000)) / (seconds_per_day * 7) ) / double( 52 ); + double weight = int64_t( (current_time_point().sec_since_epoch() - (block_timestamp::block_timestamp_epoch / 1000)) / (seconds_per_day * 7) ) / double( 52 ); return double(staked) * std::pow( 2, weight ); } @@ -205,7 +204,7 @@ namespace eosiosystem { new_vote_weight += voter->proxied_vote_weight; } - boost::container::flat_map > producer_deltas; + std::map > producer_deltas; if ( voter->last_vote_weight > 0 ) { if( voter->proxy ) { auto old_proxy = _voters.find( voter->proxy.value ); diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index c20d64165..bb08ca409 100755 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include #include diff --git a/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp b/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp index c887df431..6833c94a2 100755 --- a/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp +++ b/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include namespace eosio { /** @@ -10,10 +10,10 @@ namespace eosio { * @ingroup eosiocontracts * eosio.wrap contract simplifies Block Producer superuser actions by making them more readable and easier to audit. - * @details It does not grant block producers any additional powers that do not already exist within the - * system. Currently, 15/21 block producers can already change an account's keys or modify an - * account's contract at the request of ECAF or an account's owner. However, the current method - * is opaque and leaves undesirable side effects on specific system accounts. + * @details It does not grant block producers any additional powers that do not already exist within the + * system. Currently, 15/21 block producers can already change an account's keys or modify an + * account's contract at the request of ECAF or an account's owner. However, the current method + * is opaque and leaves undesirable side effects on specific system accounts. * eosio.wrap allows for a cleaner method of implementing these important governance actions. * @{ */ @@ -23,14 +23,14 @@ namespace eosio { /** * Execute action. - * + * * @details Execute a transaction while bypassing regular authorization checks. - * + * * @param executer - account executing the transaction, * @param trx - the transaction to be executed. - * + * * @pre Requires authorization of eosio.wrap which needs to be a privileged account. - * + * * @post Deferred transaction RAM usage is billed to 'executer' */ [[eosio::action]] diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index 89f92e593..8f3c691c9 100755 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -10,7 +10,8 @@ void wrap::exec( ignore, ignore ) { require_auth( executer ); - send_deferred( (uint128_t(executer.value) << 64) | current_time(), executer.value, _ds.pos(), _ds.remaining() ); + send_deferred( (uint128_t(executer.value) << 64) | (uint64_t)current_time_point().time_since_epoch().count(), + executer, _ds.pos(), _ds.remaining() ); } } /// namespace eosio From 982d7a8b076c667c8d6bc357b92f97171e8a0012 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 25 Jun 2019 14:57:26 -0400 Subject: [PATCH 024/106] use get_self() rather than accessing _self directly --- contracts/eosio.bios/src/eosio.bios.cpp | 10 +-- contracts/eosio.msig/src/eosio.msig.cpp | 30 +++---- .../eosio.system/src/delegate_bandwidth.cpp | 14 ++-- contracts/eosio.system/src/eosio.system.cpp | 82 +++++++++---------- contracts/eosio.system/src/producer_pay.cpp | 16 ++-- contracts/eosio.system/src/rex.cpp | 26 +++--- contracts/eosio.token/src/eosio.token.cpp | 22 ++--- contracts/eosio.wrap/src/eosio.wrap.cpp | 2 +- 8 files changed, 101 insertions(+), 101 deletions(-) diff --git a/contracts/eosio.bios/src/eosio.bios.cpp b/contracts/eosio.bios/src/eosio.bios.cpp index d652ed114..8b9165cc7 100755 --- a/contracts/eosio.bios/src/eosio.bios.cpp +++ b/contracts/eosio.bios/src/eosio.bios.cpp @@ -3,7 +3,7 @@ namespace eosio { void bios::setabi( name account, const std::vector& abi ) { - abi_hash_table table(_self, _self.value); + abi_hash_table table(get_self(), get_self().value); auto itr = table.find( account.value ); if( itr == table.end() ) { table.emplace( account, [&]( auto& row ) { @@ -22,22 +22,22 @@ void bios::onerror( ignore, ignore> ) { } void bios::setpriv( name account, uint8_t is_priv ) { - require_auth( _self ); + require_auth( get_self() ); set_privileged( account, is_priv ); } void bios::setalimits( name account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ) { - require_auth( _self ); + require_auth( get_self() ); set_resource_limits( account, ram_bytes, net_weight, cpu_weight ); } void bios::setprods( std::vector schedule ) { - require_auth( _self ); + require_auth( get_self() ); set_proposed_producers( schedule ); } void bios::setparams( const eosio::blockchain_parameters& params ) { - require_auth( _self ); + require_auth( get_self() ); set_blockchain_parameters( params ); } diff --git a/contracts/eosio.msig/src/eosio.msig.cpp b/contracts/eosio.msig/src/eosio.msig.cpp index a410e13a3..e8245f564 100755 --- a/contracts/eosio.msig/src/eosio.msig.cpp +++ b/contracts/eosio.msig/src/eosio.msig.cpp @@ -26,7 +26,7 @@ void multisig::propose( ignore proposer, check( _trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); //check( trx_header.actions.size() > 0, "transaction must have at least one action" ); - proposals proptable( _self, _proposer.value ); + proposals proptable( get_self(), _proposer.value ); check( proptable.find( _proposal_name.value ) == proptable.end(), "proposal with the same name exists" ); auto packed_requested = pack(_requested); @@ -46,7 +46,7 @@ void multisig::propose( ignore proposer, prop.packed_transaction = pkd_trans; }); - approvals apptable( _self, _proposer.value ); + approvals apptable( get_self(), _proposer.value ); apptable.emplace( _proposer, [&]( auto& a ) { a.proposal_name = _proposal_name; a.requested_approvals.reserve( _requested.size() ); @@ -62,12 +62,12 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve require_auth( level ); if( proposal_hash ) { - proposals proptable( _self, proposer.value ); + proposals proptable( get_self(), proposer.value ); auto& prop = proptable.get( proposal_name.value, "proposal not found" ); assert_sha256( prop.packed_transaction.data(), prop.packed_transaction.size(), *proposal_hash ); } - approvals apptable( _self, proposer.value ); + approvals apptable( get_self(), proposer.value ); auto apps_it = apptable.find( proposal_name.value ); if ( apps_it != apptable.end() ) { auto itr = std::find_if( apps_it->requested_approvals.begin(), apps_it->requested_approvals.end(), [&](const approval& a) { return a.level == level; } ); @@ -78,7 +78,7 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve a.requested_approvals.erase( itr ); }); } else { - old_approvals old_apptable( _self, proposer.value ); + old_approvals old_apptable( get_self(), proposer.value ); auto& apps = old_apptable.get( proposal_name.value, "proposal not found" ); auto itr = std::find( apps.requested_approvals.begin(), apps.requested_approvals.end(), level ); @@ -94,7 +94,7 @@ void multisig::approve( name proposer, name proposal_name, permission_level leve void multisig::unapprove( name proposer, name proposal_name, permission_level level ) { require_auth( level ); - approvals apptable( _self, proposer.value ); + approvals apptable( get_self(), proposer.value ); auto apps_it = apptable.find( proposal_name.value ); if ( apps_it != apptable.end() ) { auto itr = std::find_if( apps_it->provided_approvals.begin(), apps_it->provided_approvals.end(), [&](const approval& a) { return a.level == level; } ); @@ -104,7 +104,7 @@ void multisig::unapprove( name proposer, name proposal_name, permission_level le a.provided_approvals.erase( itr ); }); } else { - old_approvals old_apptable( _self, proposer.value ); + old_approvals old_apptable( get_self(), proposer.value ); auto& apps = old_apptable.get( proposal_name.value, "proposal not found" ); auto itr = std::find( apps.provided_approvals.begin(), apps.provided_approvals.end(), level ); check( itr != apps.provided_approvals.end(), "no approval previously granted" ); @@ -118,7 +118,7 @@ void multisig::unapprove( name proposer, name proposal_name, permission_level le void multisig::cancel( name proposer, name proposal_name, name canceler ) { require_auth( canceler ); - proposals proptable( _self, proposer.value ); + proposals proptable( get_self(), proposer.value ); auto& prop = proptable.get( proposal_name.value, "proposal not found" ); if( canceler != proposer ) { @@ -127,12 +127,12 @@ void multisig::cancel( name proposer, name proposal_name, name canceler ) { proptable.erase(prop); //remove from new table - approvals apptable( _self, proposer.value ); + approvals apptable( get_self(), proposer.value ); auto apps_it = apptable.find( proposal_name.value ); if ( apps_it != apptable.end() ) { apptable.erase(apps_it); } else { - old_approvals old_apptable( _self, proposer.value ); + old_approvals old_apptable( get_self(), proposer.value ); auto apps_it = old_apptable.find( proposal_name.value ); check( apps_it != old_apptable.end(), "proposal not found" ); old_apptable.erase(apps_it); @@ -142,17 +142,17 @@ void multisig::cancel( name proposer, name proposal_name, name canceler ) { void multisig::exec( name proposer, name proposal_name, name executer ) { require_auth( executer ); - proposals proptable( _self, proposer.value ); + proposals proptable( get_self(), proposer.value ); auto& prop = proptable.get( proposal_name.value, "proposal not found" ); transaction_header trx_header; datastream ds( prop.packed_transaction.data(), prop.packed_transaction.size() ); ds >> trx_header; check( trx_header.expiration >= eosio::time_point_sec(current_time_point()), "transaction expired" ); - approvals apptable( _self, proposer.value ); + approvals apptable( get_self(), proposer.value ); auto apps_it = apptable.find( proposal_name.value ); std::vector approvals; - invalidations inv_table( _self, _self.value ); + invalidations inv_table( get_self(), get_self().value ); if ( apps_it != apptable.end() ) { approvals.reserve( apps_it->provided_approvals.size() ); for ( auto& p : apps_it->provided_approvals ) { @@ -163,7 +163,7 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { } apptable.erase(apps_it); } else { - old_approvals old_apptable( _self, proposer.value ); + old_approvals old_apptable( get_self(), proposer.value ); auto& apps = old_apptable.get( proposal_name.value, "proposal not found" ); for ( auto& level : apps.provided_approvals ) { auto it = inv_table.find( level.actor.value ); @@ -190,7 +190,7 @@ void multisig::exec( name proposer, name proposal_name, name executer ) { void multisig::invalidate( name account ) { require_auth( account ); - invalidations inv_table( _self, _self.value ); + invalidations inv_table( get_self(), get_self().value ); auto it = inv_table.find( account.value ); if ( it == inv_table.end() ) { inv_table.emplace( account, [&](auto& i) { diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 71fb2169d..8449addb1 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -139,7 +139,7 @@ namespace eosiosystem { _gstate.total_ram_bytes_reserved += uint64_t(bytes_out); _gstate.total_ram_stake += quant_after_fee.amount; - user_resources_table userres( _self, receiver.value ); + user_resources_table userres( get_self(), receiver.value ); auto res_itr = userres.find( receiver.value ); if( res_itr == userres.end() ) { res_itr = userres.emplace( receiver, [&]( auto& res ) { @@ -174,7 +174,7 @@ namespace eosiosystem { check( bytes > 0, "cannot sell negative byte" ); - user_resources_table userres( _self, account.value ); + user_resources_table userres( get_self(), account.value ); auto res_itr = userres.find( account.value ); check( res_itr != userres.end(), "no resource row" ); check( res_itr->ram_bytes >= bytes, "insufficient quota" ); @@ -242,7 +242,7 @@ namespace eosiosystem { // update stake delegated from "from" to "receiver" { - del_bandwidth_table del_tbl( _self, from.value ); + del_bandwidth_table del_tbl( get_self(), from.value ); auto itr = del_tbl.find( receiver.value ); if( itr == del_tbl.end() ) { itr = del_tbl.emplace( from, [&]( auto& dbo ){ @@ -267,7 +267,7 @@ namespace eosiosystem { // update totals of "receiver" { - user_resources_table totals_tbl( _self, receiver.value ); + user_resources_table totals_tbl( get_self(), receiver.value ); auto tot_itr = totals_tbl.find( receiver.value ); if( tot_itr == totals_tbl.end() ) { tot_itr = totals_tbl.emplace( from, [&]( auto& tot ) { @@ -314,7 +314,7 @@ namespace eosiosystem { // create refund or update from existing refund if ( stake_account != source_stake_from ) { //for eosio both transfer and refund make no sense - refunds_table refunds_tbl( _self, from.value ); + refunds_table refunds_tbl( get_self(), from.value ); auto req = refunds_tbl.find( from.value ); //create/update/delete refund @@ -383,7 +383,7 @@ namespace eosiosystem { if ( need_deferred_trx ) { eosio::transaction out; out.actions.emplace_back( permission_level{from, active_permission}, - _self, "refund"_n, + get_self(), "refund"_n, from ); out.delay_sec = refund_delay_sec; @@ -459,7 +459,7 @@ namespace eosiosystem { void system_contract::refund( const name& owner ) { require_auth( owner ); - refunds_table refunds_tbl( _self, owner.value ); + refunds_table refunds_tbl( get_self(), owner.value ); auto req = refunds_tbl.find( owner.value ); check( req != refunds_tbl.end(), "refund request not found" ); check( req->request_time + seconds(refund_delay_sec) <= current_time_point(), diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b80868abc..ee3bea36b 100755 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -13,17 +13,17 @@ namespace eosiosystem { system_contract::system_contract( name s, name code, datastream ds ) :native(s,code,ds), - _voters(_self, _self.value), - _producers(_self, _self.value), - _producers2(_self, _self.value), - _global(_self, _self.value), - _global2(_self, _self.value), - _global3(_self, _self.value), - _rammarket(_self, _self.value), - _rexpool(_self, _self.value), - _rexfunds(_self, _self.value), - _rexbalance(_self, _self.value), - _rexorders(_self, _self.value) + _voters(get_self(), get_self().value), + _producers(get_self(), get_self().value), + _producers2(get_self(), get_self().value), + _global(get_self(), get_self().value), + _global2(get_self(), get_self().value), + _global3(get_self(), get_self().value), + _rammarket(get_self(), get_self().value), + _rexpool(get_self(), get_self().value), + _rexfunds(get_self(), get_self().value), + _rexbalance(get_self(), get_self().value), + _rexorders(get_self(), get_self().value) { //print( "construct system\n" ); _gstate = _global.exists() ? _global.get() : get_default_parameters(); @@ -43,13 +43,13 @@ namespace eosiosystem { } system_contract::~system_contract() { - _global.set( _gstate, _self ); - _global2.set( _gstate2, _self ); - _global3.set( _gstate3, _self ); + _global.set( _gstate, get_self() ); + _global2.set( _gstate2, get_self() ); + _global3.set( _gstate3, get_self() ); } void system_contract::setram( uint64_t max_ram_size ) { - require_auth( _self ); + require_auth( get_self() ); check( _gstate.max_ram_size < max_ram_size, "ram may only be increased" ); /// decreasing ram might result market maker issues check( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" ); @@ -87,28 +87,28 @@ namespace eosiosystem { } void system_contract::setramrate( uint16_t bytes_per_block ) { - require_auth( _self ); + require_auth( get_self() ); update_ram_supply(); _gstate2.new_ram_per_block = bytes_per_block; } void system_contract::setparams( const eosio::blockchain_parameters& params ) { - require_auth( _self ); + require_auth( get_self() ); (eosio::blockchain_parameters&)(_gstate) = params; check( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); set_blockchain_parameters( params ); } void system_contract::setpriv( const name& account, uint8_t ispriv ) { - require_auth( _self ); + require_auth( get_self() ); set_privileged( account, ispriv ); } void system_contract::setalimits( const name& account, int64_t ram, int64_t net, int64_t cpu ) { - require_auth( _self ); + require_auth( get_self() ); - user_resources_table userres( _self, account.value ); + user_resources_table userres( get_self(), account.value ); auto ritr = userres.find( account.value ); check( ritr == userres.end(), "only supports unlimited accounts" ); @@ -124,7 +124,7 @@ namespace eosiosystem { } void system_contract::setacctram( const name& account, const std::optional& ram_bytes ) { - require_auth( _self ); + require_auth( get_self() ); int64_t current_ram, current_net, current_cpu; get_resource_limits( account, current_ram, current_net, current_cpu ); @@ -136,7 +136,7 @@ namespace eosiosystem { check( vitr != _voters.end() && has_field( vitr->flags1, voter_info::flags1_fields::ram_managed ), "RAM of account is already unmanaged" ); - user_resources_table userres( _self, account.value ); + user_resources_table userres( get_self(), account.value ); auto ritr = userres.find( account.value ); ram = ram_gift_bytes; @@ -169,7 +169,7 @@ namespace eosiosystem { } void system_contract::setacctnet( const name& account, const std::optional& net_weight ) { - require_auth( _self ); + require_auth( get_self() ); int64_t current_ram, current_net, current_cpu; get_resource_limits( account, current_ram, current_net, current_cpu ); @@ -181,7 +181,7 @@ namespace eosiosystem { check( vitr != _voters.end() && has_field( vitr->flags1, voter_info::flags1_fields::net_managed ), "Network bandwidth of account is already unmanaged" ); - user_resources_table userres( _self, account.value ); + user_resources_table userres( get_self(), account.value ); auto ritr = userres.find( account.value ); if( ritr != userres.end() ) { @@ -213,7 +213,7 @@ namespace eosiosystem { } void system_contract::setacctcpu( const name& account, const std::optional& cpu_weight ) { - require_auth( _self ); + require_auth( get_self() ); int64_t current_ram, current_net, current_cpu; get_resource_limits( account, current_ram, current_net, current_cpu ); @@ -225,7 +225,7 @@ namespace eosiosystem { check( vitr != _voters.end() && has_field( vitr->flags1, voter_info::flags1_fields::cpu_managed ), "CPU bandwidth of account is already unmanaged" ); - user_resources_table userres( _self, account.value ); + user_resources_table userres( get_self(), account.value ); auto ritr = userres.find( account.value ); if( ritr != userres.end() ) { @@ -262,7 +262,7 @@ namespace eosiosystem { } void system_contract::rmvproducer( const name& producer ) { - require_auth( _self ); + require_auth( get_self() ); auto prod = _producers.find( producer.value ); check( prod != _producers.end(), "producer not found" ); _producers.modify( prod, same_payer, [&](auto& p) { @@ -271,7 +271,7 @@ namespace eosiosystem { } void system_contract::updtrevision( uint8_t revision ) { - require_auth( _self ); + require_auth( get_self() ); check( _gstate2.revision < 255, "can not increment revision" ); // prevent wrap around check( revision == _gstate2.revision + 1, "can only increment revision by one" ); check( revision <= 1, // set upper bound to greatest revision supported in the code @@ -291,7 +291,7 @@ namespace eosiosystem { check( bid.amount > 0, "insufficient bid" ); token::transfer_action transfer_act{ token_account, { {bidder, active_permission} } }; transfer_act.send( bidder, names_account, bid, std::string("bid name ")+ newname.to_string() ); - name_bid_table bids(_self, _self.value); + name_bid_table bids(get_self(), get_self().value); print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" ); auto current = bids.find( newname.value ); if( current == bids.end() ) { @@ -306,7 +306,7 @@ namespace eosiosystem { check( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); check( current->high_bidder != bidder, "account is already highest bidder" ); - bid_refund_table refunds_table(_self, newname.value); + bid_refund_table refunds_table(get_self(), newname.value); auto it = refunds_table.find( current->high_bidder.value ); if ( it != refunds_table.end() ) { @@ -321,8 +321,8 @@ namespace eosiosystem { } transaction t; - t.actions.emplace_back( permission_level{_self, active_permission}, - _self, "bidrefund"_n, + t.actions.emplace_back( permission_level{get_self(), active_permission}, + get_self(), "bidrefund"_n, std::make_tuple( current->high_bidder, newname ) ); t.delay_sec = 0; @@ -339,7 +339,7 @@ namespace eosiosystem { } void system_contract::bidrefund( const name& bidder, const name& newname ) { - bid_refund_table refunds_table(_self, newname.value); + bid_refund_table refunds_table(get_self(), newname.value); auto it = refunds_table.find( bidder.value ); check( it != refunds_table.end(), "refund not found" ); @@ -362,7 +362,7 @@ namespace eosiosystem { ignore owner, ignore active ) { - if( creator != _self ) { + if( creator != get_self() ) { uint64_t tmp = newact.value >> 4; bool has_dot = false; @@ -373,7 +373,7 @@ namespace eosiosystem { if( has_dot ) { // or is less than 12 characters auto suffix = newact.suffix(); if( suffix == newact ) { - name_bid_table bids(_self, _self.value); + name_bid_table bids(get_self(), get_self().value); auto current = bids.find( newact.value ); check( current != bids.end(), "no active bid for name" ); check( current->high_bidder == creator, "only highest bidder can claim" ); @@ -385,7 +385,7 @@ namespace eosiosystem { } } - user_resources_table userres( _self, newact.value); + user_resources_table userres( get_self(), newact.value); userres.emplace( newact, [&]( auto& res ) { res.owner = newact; @@ -397,7 +397,7 @@ namespace eosiosystem { } void native::setabi( const name& acnt, const std::vector& abi ) { - eosio::multi_index< "abihash"_n, abi_hash > table(_self, _self.value); + eosio::multi_index< "abihash"_n, abi_hash > table(get_self(), get_self().value); auto itr = table.find( acnt.value ); if( itr == table.end() ) { table.emplace( acnt, [&]( auto& row ) { @@ -412,7 +412,7 @@ namespace eosiosystem { } void system_contract::init( unsigned_int version, const symbol& core ) { - require_auth( _self ); + require_auth( get_self() ); check( version.value == 0, "unsupported version for init action" ); auto itr = _rammarket.find(ramcore_symbol.raw()); @@ -422,7 +422,7 @@ namespace eosiosystem { check( system_token_supply.symbol == core, "specified core symbol does not exist (precision mismatch)" ); check( system_token_supply.amount > 0, "system token supply must be greater than 0" ); - _rammarket.emplace( _self, [&]( auto& m ) { + _rammarket.emplace( get_self(), [&]( auto& m ) { m.supply.amount = 100000000000000ll; m.supply.symbol = ramcore_symbol; m.base.balance.amount = int64_t(_gstate.free_ram()); @@ -431,8 +431,8 @@ namespace eosiosystem { m.quote.balance.symbol = core; }); - token::open_action open_act{ token_account, { {_self, active_permission} } }; - open_act.send( rex_account, core, _self ); + token::open_action open_act{ token_account, { {get_self(), active_permission} } }; + open_act.send( rex_account, core, get_self() ); } } /// eosio.system diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index 67d0d99a5..e07770026 100755 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -18,7 +18,7 @@ namespace eosiosystem { void system_contract::onblock( ignore ) { using namespace eosio; - require_auth(_self); + require_auth(get_self()); block_timestamp timestamp; name producer; @@ -54,7 +54,7 @@ namespace eosiosystem { update_elected_producers( timestamp ); if( (timestamp.slot - _gstate.last_name_close.slot) > blocks_per_day ) { - name_bid_table bids(_self, _self.value); + name_bid_table bids(get_self(), get_self().value); auto idx = bids.get_index<"highbid"_n>(); auto highest = idx.lower_bound( std::numeric_limits::max()/2 ); if( highest != idx.end() && @@ -98,14 +98,14 @@ namespace eosiosystem { auto to_per_block_pay = to_producers / votepay_factor; auto to_per_vote_pay = to_producers - to_per_block_pay; { - token::issue_action issue_act{ token_account, { {_self, active_permission} } }; - issue_act.send( _self, asset(new_tokens, core_symbol()), "issue tokens for producer pay and savings" ); + token::issue_action issue_act{ token_account, { {get_self(), active_permission} } }; + issue_act.send( get_self(), asset(new_tokens, core_symbol()), "issue tokens for producer pay and savings" ); } { - token::transfer_action transfer_act{ token_account, { {_self, active_permission} } }; - transfer_act.send( _self, saving_account, asset(to_savings, core_symbol()), "unallocated inflation" ); - transfer_act.send( _self, bpay_account, asset(to_per_block_pay, core_symbol()), "fund per-block bucket" ); - transfer_act.send( _self, vpay_account, asset(to_per_vote_pay, core_symbol()), "fund per-vote bucket" ); + token::transfer_action transfer_act{ token_account, { {get_self(), active_permission} } }; + transfer_act.send( get_self(), saving_account, asset(to_savings, core_symbol()), "unallocated inflation" ); + transfer_act.send( get_self(), bpay_account, asset(to_per_block_pay, core_symbol()), "fund per-block bucket" ); + transfer_act.send( get_self(), vpay_account, asset(to_per_vote_pay, core_symbol()), "fund per-vote bucket" ); } _gstate.pervote_bucket += to_per_vote_pay; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 8e737532b..34b45218b 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -59,7 +59,7 @@ namespace eosiosystem { check_voting_requirement( owner ); { - del_bandwidth_table dbw_table( _self, owner.value ); + del_bandwidth_table dbw_table( get_self(), owner.value ); auto del_itr = dbw_table.require_find( receiver.value, "delegated bandwidth record does not exist" ); check( from_net.amount <= del_itr->net_weight.amount, "amount exceeds tokens staked for net"); check( from_cpu.amount <= del_itr->cpu_weight.amount, "amount exceeds tokens staked for cpu"); @@ -152,7 +152,7 @@ namespace eosiosystem { { require_auth( from ); - rex_cpu_loan_table cpu_loans( _self, _self.value ); + rex_cpu_loan_table cpu_loans( get_self(), get_self().value ); int64_t rented_tokens = rent_rex( cpu_loans, from, receiver, loan_payment, loan_fund ); update_resource_limits( from, receiver, 0, rented_tokens ); } @@ -161,7 +161,7 @@ namespace eosiosystem { { require_auth( from ); - rex_net_loan_table net_loans( _self, _self.value ); + rex_net_loan_table net_loans( get_self(), get_self().value ); int64_t rented_tokens = rent_rex( net_loans, from, receiver, loan_payment, loan_fund ); update_resource_limits( from, receiver, rented_tokens, 0 ); } @@ -170,7 +170,7 @@ namespace eosiosystem { { require_auth( from ); - rex_cpu_loan_table cpu_loans( _self, _self.value ); + rex_cpu_loan_table cpu_loans( get_self(), get_self().value ); fund_rex_loan( cpu_loans, from, loan_num, payment ); } @@ -178,7 +178,7 @@ namespace eosiosystem { { require_auth( from ); - rex_net_loan_table net_loans( _self, _self.value ); + rex_net_loan_table net_loans( get_self(), get_self().value ); fund_rex_loan( net_loans, from, loan_num, payment ); } @@ -186,7 +186,7 @@ namespace eosiosystem { { require_auth( from ); - rex_cpu_loan_table cpu_loans( _self, _self.value ); + rex_cpu_loan_table cpu_loans( get_self(), get_self().value ); defund_rex_loan( cpu_loans, from, loan_num, amount ); } @@ -194,7 +194,7 @@ namespace eosiosystem { { require_auth( from ); - rex_net_loan_table net_loans( _self, _self.value ); + rex_net_loan_table net_loans( get_self(), get_self().value ); defund_rex_loan( net_loans, from, loan_num, amount ); } @@ -322,11 +322,11 @@ namespace eosiosystem { /// check for any outstanding loans or rex fund { - rex_cpu_loan_table cpu_loans( _self, _self.value ); + rex_cpu_loan_table cpu_loans( get_self(), get_self().value ); auto cpu_idx = cpu_loans.get_index<"byowner"_n>(); bool no_outstanding_cpu_loans = ( cpu_idx.find( owner.value ) == cpu_idx.end() ); - rex_net_loan_table net_loans( _self, _self.value ); + rex_net_loan_table net_loans( get_self(), get_self().value ); auto net_idx = net_loans.get_index<"byowner"_n>(); bool no_outstanding_net_loans = ( net_idx.find( owner.value ) == net_idx.end() ); @@ -362,7 +362,7 @@ namespace eosiosystem { return; } - user_resources_table totals_tbl( _self, receiver.value ); + user_resources_table totals_tbl( get_self(), receiver.value ); auto tot_itr = totals_tbl.find( receiver.value ); if ( tot_itr == totals_tbl.end() ) { check( 0 <= delta_net && 0 <= delta_cpu, "logic error, should not occur"); @@ -551,7 +551,7 @@ namespace eosiosystem { /// process cpu loans { - rex_cpu_loan_table cpu_loans( _self, _self.value ); + rex_cpu_loan_table cpu_loans( get_self(), get_self().value ); auto cpu_idx = cpu_loans.get_index<"byexpr"_n>(); for ( uint16_t i = 0; i < max; ++i ) { auto itr = cpu_idx.begin(); @@ -568,7 +568,7 @@ namespace eosiosystem { /// process net loans { - rex_net_loan_table net_loans( _self, _self.value ); + rex_net_loan_table net_loans( get_self(), get_self().value ); auto net_idx = net_loans.get_index<"byexpr"_n>(); for ( uint16_t i = 0; i < max; ++i ) { auto itr = net_idx.begin(); @@ -920,7 +920,7 @@ namespace eosiosystem { auto itr = _rexpool.begin(); if ( !rex_system_initialized() ) { /// initialize REX pool - _rexpool.emplace( _self, [&]( auto& rp ) { + _rexpool.emplace( get_self(), [&]( auto& rp ) { rex_received.amount = payment.amount * rex_ratio; rp.total_lendable = payment; rp.total_lent = asset( 0, core_symbol() ); diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index a0b5ad631..1e7d97b0f 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -5,18 +5,18 @@ namespace eosio { void token::create( const name& issuer, const asset& maximum_supply ) { - require_auth( _self ); + require_auth( get_self() ); auto sym = maximum_supply.symbol; check( sym.is_valid(), "invalid symbol name" ); check( maximum_supply.is_valid(), "invalid supply"); check( maximum_supply.amount > 0, "max-supply must be positive"); - stats statstable( _self, sym.code().raw() ); + stats statstable( get_self(), sym.code().raw() ); auto existing = statstable.find( sym.code().raw() ); check( existing == statstable.end(), "token with symbol already exists" ); - statstable.emplace( _self, [&]( auto& s ) { + statstable.emplace( get_self(), [&]( auto& s ) { s.supply.symbol = maximum_supply.symbol; s.max_supply = maximum_supply; s.issuer = issuer; @@ -30,7 +30,7 @@ void token::issue( const name& to, const asset& quantity, const string& memo ) check( sym.is_valid(), "invalid symbol name" ); check( memo.size() <= 256, "memo has more than 256 bytes" ); - stats statstable( _self, sym.code().raw() ); + stats statstable( get_self(), sym.code().raw() ); auto existing = statstable.find( sym.code().raw() ); check( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); const auto& st = *existing; @@ -56,7 +56,7 @@ void token::retire( const asset& quantity, const string& memo ) check( sym.is_valid(), "invalid symbol name" ); check( memo.size() <= 256, "memo has more than 256 bytes" ); - stats statstable( _self, sym.code().raw() ); + stats statstable( get_self(), sym.code().raw() ); auto existing = statstable.find( sym.code().raw() ); check( existing != statstable.end(), "token with symbol does not exist" ); const auto& st = *existing; @@ -83,7 +83,7 @@ void token::transfer( const name& from, require_auth( from ); check( is_account( to ), "to account does not exist"); auto sym = quantity.symbol.code(); - stats statstable( _self, sym.raw() ); + stats statstable( get_self(), sym.raw() ); const auto& st = statstable.get( sym.raw() ); require_recipient( from ); @@ -101,7 +101,7 @@ void token::transfer( const name& from, } void token::sub_balance( const name& owner, const asset& value ) { - accounts from_acnts( _self, owner.value ); + accounts from_acnts( get_self(), owner.value ); const auto& from = from_acnts.get( value.symbol.code().raw(), "no balance object found" ); check( from.balance.amount >= value.amount, "overdrawn balance" ); @@ -113,7 +113,7 @@ void token::sub_balance( const name& owner, const asset& value ) { void token::add_balance( const name& owner, const asset& value, const name& ram_payer ) { - accounts to_acnts( _self, owner.value ); + accounts to_acnts( get_self(), owner.value ); auto to = to_acnts.find( value.symbol.code().raw() ); if( to == to_acnts.end() ) { to_acnts.emplace( ram_payer, [&]( auto& a ){ @@ -132,11 +132,11 @@ void token::open( const name& owner, const symbol& symbol, const name& ram_payer auto sym_code_raw = symbol.code().raw(); - stats statstable( _self, sym_code_raw ); + stats statstable( get_self(), sym_code_raw ); const auto& st = statstable.get( sym_code_raw, "symbol does not exist" ); check( st.supply.symbol == symbol, "symbol precision mismatch" ); - accounts acnts( _self, owner.value ); + accounts acnts( get_self(), owner.value ); auto it = acnts.find( sym_code_raw ); if( it == acnts.end() ) { acnts.emplace( ram_payer, [&]( auto& a ){ @@ -148,7 +148,7 @@ void token::open( const name& owner, const symbol& symbol, const name& ram_payer void token::close( const name& owner, const symbol& symbol ) { require_auth( owner ); - accounts acnts( _self, owner.value ); + accounts acnts( get_self(), owner.value ); auto it = acnts.find( symbol.code().raw() ); check( it != acnts.end(), "Balance row already deleted or never existed. Action won't have any effect." ); check( it->balance.amount == 0, "Cannot close because the balance is not zero." ); diff --git a/contracts/eosio.wrap/src/eosio.wrap.cpp b/contracts/eosio.wrap/src/eosio.wrap.cpp index 8f3c691c9..94be6937f 100755 --- a/contracts/eosio.wrap/src/eosio.wrap.cpp +++ b/contracts/eosio.wrap/src/eosio.wrap.cpp @@ -3,7 +3,7 @@ namespace eosio { void wrap::exec( ignore, ignore ) { - require_auth( _self ); + require_auth( get_self() ); name executer; _ds >> executer; From 806ff922084c8cef57b3b0e2019e717d352944a9 Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 25 Jun 2019 16:54:50 -0400 Subject: [PATCH 025/106] compile eosio.system contract with multiple cpp files --- contracts/eosio.system/CMakeLists.txt | 10 ++- .../include/eosio.system/eosio.system.hpp | 70 ++++++++++++++- .../include/eosio.system/exchange_state.hpp | 3 +- .../include/eosio.system/native.hpp | 21 +---- .../eosio.system/src/delegate_bandwidth.cpp | 71 ++------------- contracts/eosio.system/src/eosio.system.cpp | 89 +++---------------- contracts/eosio.system/src/exchange_state.cpp | 8 +- contracts/eosio.system/src/name_bidding.cpp | 80 +++++++++++++++++ contracts/eosio.system/src/native.cpp | 27 ++++++ contracts/eosio.system/src/producer_pay.cpp | 17 +--- contracts/eosio.system/src/rex.cpp | 4 + contracts/eosio.system/src/voting.cpp | 6 +- 12 files changed, 222 insertions(+), 184 deletions(-) create mode 100644 contracts/eosio.system/src/name_bidding.cpp create mode 100644 contracts/eosio.system/src/native.cpp diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index e99eb37bd..3f9090846 100755 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -1,4 +1,12 @@ -add_contract(eosio.system eosio.system ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.system.cpp) +add_contract(eosio.system eosio.system + ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.system.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/delegate_bandwidth.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/exchange_state.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/native.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/producer_pay.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp +) target_include_directories(eosio.system PUBLIC diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index e5657f77d..94d064413 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -31,13 +31,12 @@ namespace eosiosystem { using eosio::const_mem_fun; using eosio::datastream; using eosio::indexed_by; - using eosio::microseconds; using eosio::name; + using eosio::same_payer; using eosio::symbol; using eosio::symbol_code; using eosio::time_point; using eosio::time_point_sec; - using eosio::microseconds; using eosio::unsigned_int; template @@ -59,6 +58,21 @@ namespace eosiosystem { return ( flags & ~static_cast(field) ); } + static constexpr uint32_t seconds_per_year = 52 * 7 * 24 * 3600; + static constexpr uint32_t seconds_per_day = 24 * 3600; + static constexpr int64_t useconds_per_year = int64_t(seconds_per_year) * 1000'000ll; + static constexpr int64_t useconds_per_day = int64_t(seconds_per_day) * 1000'000ll; + static constexpr uint32_t blocks_per_day = 2 * seconds_per_day; // half seconds per day + + static constexpr int64_t min_activated_stake = 150'000'000'0000; + static constexpr int64_t ram_gift_bytes = 1400; + static constexpr int64_t min_pervote_daily_pay = 100'0000; + static constexpr double continuous_rate = 0.04879; // 5% annual rate + static constexpr int64_t inflation_pay_factor = 5; // 20% of the inflation + static constexpr int64_t votepay_factor = 4; // 25% of the producer pay + static constexpr uint32_t refund_delay_sec = 3 * seconds_per_day; + + /** * * @defgroup eosiosystem eosio.system @@ -294,8 +308,56 @@ namespace eosiosystem { */ typedef eosio::singleton< "global3"_n, eosio_global_state3 > global_state3_singleton; - // static constexpr uint32_t max_inflation_rate = 5; // 5% annual inflation - static constexpr uint32_t seconds_per_day = 24 * 3600; + struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { + name owner; + asset net_weight; + asset cpu_weight; + int64_t ram_bytes = 0; + + bool is_empty()const { return net_weight.amount == 0 && cpu_weight.amount == 0 && ram_bytes == 0; } + uint64_t primary_key()const { return owner.value; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( user_resources, (owner)(net_weight)(cpu_weight)(ram_bytes) ) + }; + + /** + * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. + */ + struct [[eosio::table, eosio::contract("eosio.system")]] delegated_bandwidth { + name from; + name to; + asset net_weight; + asset cpu_weight; + + bool is_empty()const { return net_weight.amount == 0 && cpu_weight.amount == 0; } + uint64_t primary_key()const { return to.value; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight) ) + + }; + + struct [[eosio::table, eosio::contract("eosio.system")]] refund_request { + name owner; + time_point_sec request_time; + eosio::asset net_amount; + eosio::asset cpu_amount; + + bool is_empty()const { return net_amount.amount == 0 && cpu_amount.amount == 0; } + uint64_t primary_key()const { return owner.value; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_amount) ) + }; + + /** + * These tables are designed to be constructed in the scope of the relevant user, this + * facilitates simpler API for per-user queries + */ + typedef eosio::multi_index< "userres"_n, user_resources > user_resources_table; + typedef eosio::multi_index< "delband"_n, delegated_bandwidth > del_bandwidth_table; + typedef eosio::multi_index< "refunds"_n, refund_request > refunds_table; /** * `rex_pool` structure underlying the rex pool table. diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 15988e04a..999ea7d71 100755 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -1,9 +1,10 @@ #pragma once #include +#include namespace eosiosystem { - + using eosio::asset; using eosio::symbol; diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index 6ae7a6c7a..40a428504 100755 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -22,22 +22,9 @@ namespace eosio { void preactivate_feature( const ::capi_checksum256* feature_digest ); } } -} -namespace eosio { - bool is_feature_activated( const eosio::checksum256& feature_digest ) { - auto feature_digest_data = feature_digest.extract_as_byte_array(); - return internal_use_do_not_use::is_feature_activated( - reinterpret_cast( feature_digest_data.data() ) - ); - } - - void preactivate_feature( const eosio::checksum256& feature_digest ) { - auto feature_digest_data = feature_digest.extract_as_byte_array(); - internal_use_do_not_use::preactivate_feature( - reinterpret_cast( feature_digest_data.data() ) - ); - } + bool is_feature_activated( const eosio::checksum256& feature_digest ); + void preactivate_feature( const eosio::checksum256& feature_digest ); } namespace eosiosystem { @@ -280,9 +267,7 @@ namespace eosiosystem { * @param sent_trx - the deferred transaction that failed. */ [[eosio::action]] - void onerror( ignore sender_id, ignore> sent_trx ) { - eosio::check( false, "the onerror action cannot be called directly" ); - } + void onerror( ignore sender_id, ignore> sent_trx ); /** * Set abi action. diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index 8449addb1..e1ecbd1f2 100755 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -8,76 +8,19 @@ #include #include -#include -#include +#include "name_bidding.cpp" +// Unfortunately, this is needed until CDT fixes the duplicate symbol error with eosio::send_deferred namespace eosiosystem { using eosio::asset; using eosio::const_mem_fun; + using eosio::current_time_point; using eosio::indexed_by; using eosio::permission_level; + using eosio::seconds; using eosio::time_point_sec; - - using std::map; - using std::pair; - - static constexpr uint32_t refund_delay_sec = 3*24*3600; - static constexpr int64_t ram_gift_bytes = 1400; - - struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { - name owner; - asset net_weight; - asset cpu_weight; - int64_t ram_bytes = 0; - - bool is_empty()const { return net_weight.amount == 0 && cpu_weight.amount == 0 && ram_bytes == 0; } - uint64_t primary_key()const { return owner.value; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( user_resources, (owner)(net_weight)(cpu_weight)(ram_bytes) ) - }; - - - /** - * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. - */ - struct [[eosio::table, eosio::contract("eosio.system")]] delegated_bandwidth { - name from; - name to; - asset net_weight; - asset cpu_weight; - - bool is_empty()const { return net_weight.amount == 0 && cpu_weight.amount == 0; } - uint64_t primary_key()const { return to.value; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight) ) - - }; - - struct [[eosio::table, eosio::contract("eosio.system")]] refund_request { - name owner; - time_point_sec request_time; - eosio::asset net_amount; - eosio::asset cpu_amount; - - bool is_empty()const { return net_amount.amount == 0 && cpu_amount.amount == 0; } - uint64_t primary_key()const { return owner.value; } - - // explicit serialization macro is not necessary, used here only to improve compilation time - EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_amount) ) - }; - - /** - * These tables are designed to be constructed in the scope of the relevant user, this - * facilitates simpler API for per-user queries - */ - typedef eosio::multi_index< "userres"_n, user_resources > user_resources_table; - typedef eosio::multi_index< "delband"_n, delegated_bandwidth > del_bandwidth_table; - typedef eosio::multi_index< "refunds"_n, refund_request > refunds_table; - - + using eosio::token; /** * This action will buy an exact amount of ram and bill the payer the current market price. @@ -387,10 +330,10 @@ namespace eosiosystem { from ); out.delay_sec = refund_delay_sec; - cancel_deferred( from.value ); // TODO: Remove this line when replacing deferred trxs is fixed + eosio::cancel_deferred( from.value ); // TODO: Remove this line when replacing deferred trxs is fixed out.send( from.value, from, true ); } else { - cancel_deferred( from.value ); + eosio::cancel_deferred( from.value ); } auto transfer_amount = net_balance + cpu_balance; diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index ee3bea36b..4644b13ed 100755 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -1,16 +1,14 @@ -#include -#include - #include +#include -#include "producer_pay.cpp" -#include "delegate_bandwidth.cpp" -#include "voting.cpp" -#include "exchange_state.cpp" -#include "rex.cpp" +#include +#include namespace eosiosystem { + using eosio::current_time_point; + using eosio::token; + system_contract::system_contract( name s, name code, datastream ds ) :native(s,code,ds), _voters(get_self(), get_self().value), @@ -69,7 +67,7 @@ namespace eosiosystem { } void system_contract::update_ram_supply() { - auto cbt = current_block_time(); + auto cbt = eosio::current_block_time(); if( cbt <= _gstate2.last_ram_increase ) return; @@ -279,74 +277,7 @@ namespace eosiosystem { _gstate2.revision = revision; } - void system_contract::bidname( const name& bidder, const name& newname, const asset& bid ) { - require_auth( bidder ); - check( newname.suffix() == newname, "you can only bid on top-level suffix" ); - - check( (bool)newname, "the empty name is not a valid account name to bid on" ); - check( (newname.value & 0xFull) == 0, "13 character names are not valid account names to bid on" ); - check( (newname.value & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" ); - check( !is_account( newname ), "account already exists" ); - check( bid.symbol == core_symbol(), "asset must be system token" ); - check( bid.amount > 0, "insufficient bid" ); - token::transfer_action transfer_act{ token_account, { {bidder, active_permission} } }; - transfer_act.send( bidder, names_account, bid, std::string("bid name ")+ newname.to_string() ); - name_bid_table bids(get_self(), get_self().value); - print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" ); - auto current = bids.find( newname.value ); - if( current == bids.end() ) { - bids.emplace( bidder, [&]( auto& b ) { - b.newname = newname; - b.high_bidder = bidder; - b.high_bid = bid.amount; - b.last_bid_time = current_time_point(); - }); - } else { - check( current->high_bid > 0, "this auction has already closed" ); - check( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); - check( current->high_bidder != bidder, "account is already highest bidder" ); - - bid_refund_table refunds_table(get_self(), newname.value); - - auto it = refunds_table.find( current->high_bidder.value ); - if ( it != refunds_table.end() ) { - refunds_table.modify( it, same_payer, [&](auto& r) { - r.amount += asset( current->high_bid, core_symbol() ); - }); - } else { - refunds_table.emplace( bidder, [&](auto& r) { - r.bidder = current->high_bidder; - r.amount = asset( current->high_bid, core_symbol() ); - }); - } - - transaction t; - t.actions.emplace_back( permission_level{get_self(), active_permission}, - get_self(), "bidrefund"_n, - std::make_tuple( current->high_bidder, newname ) - ); - t.delay_sec = 0; - uint128_t deferred_id = (uint128_t(newname.value) << 64) | current->high_bidder.value; - cancel_deferred( deferred_id ); - t.send( deferred_id, bidder ); - - bids.modify( current, bidder, [&]( auto& b ) { - b.high_bidder = bidder; - b.high_bid = bid.amount; - b.last_bid_time = current_time_point(); - }); - } - } - - void system_contract::bidrefund( const name& bidder, const name& newname ) { - bid_refund_table refunds_table(get_self(), newname.value); - auto it = refunds_table.find( bidder.value ); - check( it != refunds_table.end(), "refund not found" ); - token::transfer_action transfer_act{ token_account, { {names_account, active_permission}, {bidder, active_permission} } }; - transfer_act.send( names_account, bidder, asset(it->amount), std::string("refund bid on name ")+(name{newname}).to_string() ); - refunds_table.erase( it ); - } /** * Called after a new account is created. This code enforces resource-limits rules @@ -385,7 +316,7 @@ namespace eosiosystem { } } - user_resources_table userres( get_self(), newact.value); + user_resources_table userres( get_self(), newact.value ); userres.emplace( newact, [&]( auto& res ) { res.owner = newact; @@ -402,11 +333,11 @@ namespace eosiosystem { if( itr == table.end() ) { table.emplace( acnt, [&]( auto& row ) { row.owner = acnt; - row.hash = sha256(const_cast(abi.data()), abi.size()); + row.hash = eosio::sha256(const_cast(abi.data()), abi.size()); }); } else { table.modify( itr, same_payer, [&]( auto& row ) { - row.hash = sha256(const_cast(abi.data()), abi.size()); + row.hash = eosio::sha256(const_cast(abi.data()), abi.size()); }); } } diff --git a/contracts/eosio.system/src/exchange_state.cpp b/contracts/eosio.system/src/exchange_state.cpp index 48ad24a91..8f9734bcb 100755 --- a/contracts/eosio.system/src/exchange_state.cpp +++ b/contracts/eosio.system/src/exchange_state.cpp @@ -1,7 +1,13 @@ #include +#include + +#include + namespace eosiosystem { + using eosio::check; + asset exchange_state::convert_to_exchange( connector& reserve, const asset& payment ) { const double S0 = supply.amount; @@ -24,7 +30,7 @@ namespace eosiosystem { const double Fi = double(1) / reserve.weight; double dR = R0 * ( std::pow(1. + dS / S0, Fi) - 1. ); // dR < 0 since dS < 0 - if ( dR > 0 ) dR = 0; // rounding errors + if ( dR > 0 ) dR = 0; // rounding errors reserve.balance.amount -= int64_t(-dR); supply -= tokens; return asset( int64_t(-dR), reserve.balance.symbol ); diff --git a/contracts/eosio.system/src/name_bidding.cpp b/contracts/eosio.system/src/name_bidding.cpp new file mode 100644 index 000000000..d08aed653 --- /dev/null +++ b/contracts/eosio.system/src/name_bidding.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include + +namespace eosiosystem { + + using eosio::current_time_point; + using eosio::token; + + void system_contract::bidname( const name& bidder, const name& newname, const asset& bid ) { + require_auth( bidder ); + check( newname.suffix() == newname, "you can only bid on top-level suffix" ); + + check( (bool)newname, "the empty name is not a valid account name to bid on" ); + check( (newname.value & 0xFull) == 0, "13 character names are not valid account names to bid on" ); + check( (newname.value & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" ); + check( !is_account( newname ), "account already exists" ); + check( bid.symbol == core_symbol(), "asset must be system token" ); + check( bid.amount > 0, "insufficient bid" ); + token::transfer_action transfer_act{ token_account, { {bidder, active_permission} } }; + transfer_act.send( bidder, names_account, bid, std::string("bid name ")+ newname.to_string() ); + name_bid_table bids(get_self(), get_self().value); + print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" ); + auto current = bids.find( newname.value ); + if( current == bids.end() ) { + bids.emplace( bidder, [&]( auto& b ) { + b.newname = newname; + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time_point(); + }); + } else { + check( current->high_bid > 0, "this auction has already closed" ); + check( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); + check( current->high_bidder != bidder, "account is already highest bidder" ); + + bid_refund_table refunds_table(get_self(), newname.value); + + auto it = refunds_table.find( current->high_bidder.value ); + if ( it != refunds_table.end() ) { + refunds_table.modify( it, same_payer, [&](auto& r) { + r.amount += asset( current->high_bid, core_symbol() ); + }); + } else { + refunds_table.emplace( bidder, [&](auto& r) { + r.bidder = current->high_bidder; + r.amount = asset( current->high_bid, core_symbol() ); + }); + } + + eosio::transaction t; + t.actions.emplace_back( permission_level{get_self(), active_permission}, + get_self(), "bidrefund"_n, + std::make_tuple( current->high_bidder, newname ) + ); + t.delay_sec = 0; + uint128_t deferred_id = (uint128_t(newname.value) << 64) | current->high_bidder.value; + eosio::cancel_deferred( deferred_id ); + t.send( deferred_id, bidder ); + + bids.modify( current, bidder, [&]( auto& b ) { + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time_point(); + }); + } + } + + void system_contract::bidrefund( const name& bidder, const name& newname ) { + bid_refund_table refunds_table(get_self(), newname.value); + auto it = refunds_table.find( bidder.value ); + check( it != refunds_table.end(), "refund not found" ); + + token::transfer_action transfer_act{ token_account, { {names_account, active_permission}, {bidder, active_permission} } }; + transfer_act.send( names_account, bidder, asset(it->amount), std::string("refund bid on name ")+(name{newname}).to_string() ); + refunds_table.erase( it ); + } + +} diff --git a/contracts/eosio.system/src/native.cpp b/contracts/eosio.system/src/native.cpp new file mode 100644 index 000000000..a8f763040 --- /dev/null +++ b/contracts/eosio.system/src/native.cpp @@ -0,0 +1,27 @@ +#include + +#include + +namespace eosio { + bool is_feature_activated( const eosio::checksum256& feature_digest ) { + auto feature_digest_data = feature_digest.extract_as_byte_array(); + return internal_use_do_not_use::is_feature_activated( + reinterpret_cast( feature_digest_data.data() ) + ); + } + + void preactivate_feature( const eosio::checksum256& feature_digest ) { + auto feature_digest_data = feature_digest.extract_as_byte_array(); + internal_use_do_not_use::preactivate_feature( + reinterpret_cast( feature_digest_data.data() ) + ); + } +} + +namespace eosiosystem { + + void native::onerror( ignore, ignore> ) { + eosio::check( false, "the onerror action cannot be called directly" ); + } + +} diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index e07770026..4f9848f86 100755 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -3,17 +3,9 @@ namespace eosiosystem { - const int64_t min_pervote_daily_pay = 100'0000; - const int64_t min_activated_stake = 150'000'000'0000; - const double continuous_rate = 0.04879; // 5% annual rate - const int64_t inflation_pay_factor = 5; // 20% of the inflation - const int64_t votepay_factor = 4; // 25% of the producer pay - const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year - const uint32_t seconds_per_year = 52*7*24*3600; - const uint32_t blocks_per_day = 2 * 24 * 3600; - const uint32_t blocks_per_hour = 2 * 3600; - const int64_t useconds_per_day = 24 * 3600 * int64_t(1000000); - const int64_t useconds_per_year = seconds_per_year*1000000ll; + using eosio::current_time_point; + using eosio::microseconds; + using eosio::token; void system_contract::onblock( ignore ) { using namespace eosio; @@ -73,7 +65,6 @@ namespace eosiosystem { } } - using namespace eosio; void system_contract::claimrewards( const name& owner ) { require_auth( owner ); @@ -87,7 +78,7 @@ namespace eosiosystem { check( ct - prod.last_claim_time > microseconds(useconds_per_day), "already claimed rewards within past day" ); - const asset token_supply = eosio::token::get_supply(token_account, core_symbol().code() ); + const asset token_supply = token::get_supply(token_account, core_symbol().code() ); const auto usecs_since_last_fill = (ct - _gstate.last_pervote_bucket_fill).count(); if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > time_point() ) { diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 34b45218b..4a4596e25 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -1,8 +1,12 @@ #include +#include #include namespace eosiosystem { + using eosio::current_time_point; + using eosio::token; + void system_contract::deposit( const name& owner, const asset& amount ) { require_auth( owner ); diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index cc540297d..95f1dd36a 100755 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -16,9 +15,10 @@ namespace eosiosystem { using eosio::const_mem_fun; + using eosio::current_time_point; using eosio::indexed_by; + using eosio::microseconds; using eosio::singleton; - using eosio::transaction; void system_contract::regproducer( const name& producer, const eosio::public_key& producer_key, const std::string& url, uint16_t location ) { check( url.size() < 512, "url too long" ); @@ -204,7 +204,7 @@ namespace eosiosystem { new_vote_weight += voter->proxied_vote_weight; } - std::map > producer_deltas; + std::map > producer_deltas; if ( voter->last_vote_weight > 0 ) { if( voter->proxy ) { auto old_proxy = _voters.find( voter->proxy.value ); From 509895e6d8d63881efaad7cca3c272303bcd1b03 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 26 Jun 2019 18:26:44 -0400 Subject: [PATCH 026/106] Add is_account check to token::open --- contracts/eosio.token/src/eosio.token.cpp | 3 ++- tests/eosio.token_tests.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index a0b5ad631..b1bbd4d4b 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -130,8 +130,9 @@ void token::open( const name& owner, const symbol& symbol, const name& ram_payer { require_auth( ram_payer ); - auto sym_code_raw = symbol.code().raw(); + check( is_account( owner ), "owner account does not exist" ); + auto sym_code_raw = symbol.code().raw(); stats statstable( _self, sym_code_raw ); const auto& st = statstable.get( sym_code_raw, "symbol does not exist" ); check( st.supply.symbol == symbol, "symbol precision mismatch" ); diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 654b17038..acca038a6 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -367,7 +367,10 @@ BOOST_FIXTURE_TEST_CASE( open_tests, eosio_token_tester ) try { auto bob_balance = get_account(N(bob), "0,CERO"); BOOST_REQUIRE_EQUAL(true, bob_balance.is_null() ); - BOOST_REQUIRE_EQUAL( success(), open( N(bob), "0,CERO", N(alice) ) ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("owner account does not exist"), + open( N(nonexistent), "0,CERO", N(alice) ) ); + BOOST_REQUIRE_EQUAL( success(), + open( N(bob), "0,CERO", N(alice) ) ); bob_balance = get_account(N(bob), "0,CERO"); REQUIRE_MATCHING_OBJECT( bob_balance, mvo() From f3d2013caf97b6c6ac36ede6b41c63701934c266 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 26 Jun 2019 19:46:12 -0400 Subject: [PATCH 027/106] create eosio.rex account before eosio::init action (fixes test failures) --- tests/eosio.msig_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 570fbd1ad..e28e229c0 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -414,7 +414,7 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) set_producers( {N(alice),N(bob),N(carol)} ); produce_blocks(50); - create_accounts( { N(eosio.token) } ); + create_accounts( { N(eosio.token), N(eosio.rex) } ); set_code( N(eosio.token), contracts::token_wasm() ); set_abi( N(eosio.token), contracts::token_abi().data() ); @@ -533,7 +533,7 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester set_producers( {N(alice),N(bob),N(carol), N(apple)} ); produce_blocks(50); - create_accounts( { N(eosio.token) } ); + create_accounts( { N(eosio.token), N(eosio.rex) } ); set_code( N(eosio.token), contracts::token_wasm() ); set_abi( N(eosio.token), contracts::token_abi().data() ); From 1117cf8bc5b202a57b357708630a325a4f5728e4 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 27 Jun 2019 16:46:12 -0400 Subject: [PATCH 028/106] fix double-move bug in system_contract::registration --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 5267ce555..f9349c80c 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -698,7 +698,7 @@ namespace eosiosystem { template static constexpr void call( system_contract* this_contract, Args&&... args ) { - std::invoke( P, this_contract, std::forward(args)... ); + std::invoke( P, this_contract, args... ); for_each::call( this_contract, std::forward(args)... ); } }; From a07f877273ae7f7b74fa6500a65c649392059376 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 27 Jun 2019 16:46:12 -0400 Subject: [PATCH 029/106] fix double-move bug in system_contract::registration --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6e287c465..b6a0d8d45 100755 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1283,7 +1283,7 @@ namespace eosiosystem { template static constexpr void call( system_contract* this_contract, Args&&... args ) { - std::invoke( P, this_contract, std::forward(args)... ); + std::invoke( P, this_contract, args... ); for_each::call( this_contract, std::forward(args)... ); } }; From 7463ed71e78a38cc2c6cb731b7f067aabf332925 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 26 Jun 2019 18:26:44 -0400 Subject: [PATCH 030/106] Add is_account check to token::open --- contracts/eosio.token/src/eosio.token.cpp | 3 ++- tests/eosio.token_tests.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.token/src/eosio.token.cpp b/contracts/eosio.token/src/eosio.token.cpp index d75b8448a..66a7ea99e 100755 --- a/contracts/eosio.token/src/eosio.token.cpp +++ b/contracts/eosio.token/src/eosio.token.cpp @@ -135,8 +135,9 @@ void token::open( name owner, const symbol& symbol, name ram_payer ) { require_auth( ram_payer ); - auto sym_code_raw = symbol.code().raw(); + check( is_account( owner ), "owner account does not exist" ); + auto sym_code_raw = symbol.code().raw(); stats statstable( _self, sym_code_raw ); const auto& st = statstable.get( sym_code_raw, "symbol does not exist" ); check( st.supply.symbol == symbol, "symbol precision mismatch" ); diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 8d7d73ff6..d5eccb931 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -363,7 +363,10 @@ BOOST_FIXTURE_TEST_CASE( open_tests, eosio_token_tester ) try { auto bob_balance = get_account(N(bob), "0,CERO"); BOOST_REQUIRE_EQUAL(true, bob_balance.is_null() ); - BOOST_REQUIRE_EQUAL( success(), open( N(bob), "0,CERO", N(alice) ) ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("owner account does not exist"), + open( N(nonexistent), "0,CERO", N(alice) ) ); + BOOST_REQUIRE_EQUAL( success(), + open( N(bob), "0,CERO", N(alice) ) ); bob_balance = get_account(N(bob), "0,CERO"); REQUIRE_MATCHING_OBJECT( bob_balance, mvo() From 120fa04ab75d2d66b1d3881b3a167d64efd3f9df Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 26 Jun 2019 19:46:12 -0400 Subject: [PATCH 031/106] create eosio.rex account before eosio::init action (fixes test failures) --- tests/eosio.msig_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index 39b6a5f94..7639c24a2 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -402,7 +402,7 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_all_approve, eosio_msig_tester ) set_producers( {N(alice),N(bob),N(carol)} ); produce_blocks(50); - create_accounts( { N(eosio.token) } ); + create_accounts( { N(eosio.token), N(eosio.rex) } ); set_code( N(eosio.token), contracts::token_wasm() ); set_abi( N(eosio.token), contracts::token_abi().data() ); @@ -517,7 +517,7 @@ BOOST_FIXTURE_TEST_CASE( update_system_contract_major_approve, eosio_msig_tester set_producers( {N(alice),N(bob),N(carol), N(apple)} ); produce_blocks(50); - create_accounts( { N(eosio.token) } ); + create_accounts( { N(eosio.token), N(eosio.rex) } ); set_code( N(eosio.token), contracts::token_wasm() ); set_abi( N(eosio.token), contracts::token_abi().data() ); From cf1dfdce5cc5a3de2136b5b0b0a08c7629d520dd Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 28 Jun 2019 10:59:09 -0400 Subject: [PATCH 032/106] bump version to v1.6.1 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f6c695147..a43503ed8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 6) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) #set(VERSION_SUFFIX rc3) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index 7cae0fcac..7ff18e49f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.6.0 +## Version : 1.6.1 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. From dacb6497ecd3551afda4eb36f76701fe9e0367a5 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 28 Jun 2019 16:40:43 -0400 Subject: [PATCH 033/106] bump version to v1.7.0 --- CMakeLists.txt | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e20245cc..39ddb99bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 7) set(VERSION_PATCH 0) -set(VERSION_SUFFIX rc1) +#set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/README.md b/README.md index c610475dd..8994f67ba 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.7.0-rc1 +## Version : 1.7.0 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 bios, system, msig, wrap (formerly known as sudo) and token contracts. @@ -15,7 +15,7 @@ The following unprivileged contract(s) are also part of the system. * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.0-rc2) +* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.0) * [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.1) To build the contracts and the unit tests: From c46cf7e337995dd18400836d02e607faab94edb6 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 22 Aug 2019 09:56:33 -0400 Subject: [PATCH 034/106] Implemented TravisCI for community PRs. --- .cicd/build.sh | 26 ++++++++++++++++++++++++++ .cicd/helpers/dependency-info.sh | 26 ++++++++++++++++++++++++++ .cicd/helpers/general.sh | 6 ++++++ .cicd/pipeline.yml | 23 +++++++++++++++++++++++ .cicd/tests.sh | 26 ++++++++++++++++++++++++++ .travis.yml | 16 ++++++++++++++++ pipeline.jsonc | 5 +++-- 7 files changed, 126 insertions(+), 2 deletions(-) create mode 100755 .cicd/build.sh create mode 100755 .cicd/helpers/dependency-info.sh create mode 100644 .cicd/helpers/general.sh create mode 100644 .cicd/pipeline.yml create mode 100755 .cicd/tests.sh create mode 100644 .travis.yml diff --git a/.cicd/build.sh b/.cicd/build.sh new file mode 100755 index 000000000..a80c1d9c6 --- /dev/null +++ b/.cicd/build.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail + +. ./.cicd/helpers/general.sh +. ./.cicd/helpers/dependency-info.sh + +mkdir -p $BUILD_DIR + +FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} +ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:$PATH" + +PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" +BUILD_COMMANDS="cmake .. && make -j $JOBS" + +COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" + +# Load BUILDKITE Environment Variables for use in docker run +if [[ -f $BUILDKITE_ENV_FILE ]]; then + evars="" + while read -r var; do + evars="$evars --env ${var%%=*}" + done < "$BUILDKITE_ENV_FILE" +fi + +eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh new file mode 100755 index 000000000..533bf1d5c --- /dev/null +++ b/.cicd/helpers/dependency-info.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG="$1" +[[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG='pipeline.jsonc' +[[ "$PIPELINE_CONFIG" == '' ]] && export PIPELINE_CONFIG='pipeline.json' +# read dependency file +if [[ -f "$RAW_PIPELINE_CONFIG" ]]; then + echo 'Reading pipeline configuration file...' + cat "$RAW_PIPELINE_CONFIG" | grep -Po '^[^"/]*("((?<=\\).|[^"])*"[^"/]*)*' | jq -c .\"eosio-dot-contracts\" > "$PIPELINE_CONFIG" + EOSIO_BRANCH=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies.eosio') + CDT_BRANCH=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."eosio.cdt"') + CDT_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."cdt-version"') +else + echo 'ERROR: No pipeline configuration file or dependencies file found!' + exit 1 +fi +if [[ $TRAVIS ]]; then + CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_BRANCH && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_BRANCH) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match +else + CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_BRANCH && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_BRANCH) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match +fi +test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_BRANCH | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already +echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_BRANCH\"..." + +export BRANCH=$(echo $EOSIO_BRANCH | sed 's/\//\_/') +export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt_${CDT_VERSION}-ubuntu-18.04_amd64.deb" \ No newline at end of file diff --git a/.cicd/helpers/general.sh b/.cicd/helpers/general.sh new file mode 100644 index 000000000..42b041177 --- /dev/null +++ b/.cicd/helpers/general.sh @@ -0,0 +1,6 @@ +export ROOT_DIR=$( dirname "${BASH_SOURCE[0]}" )/../.. +export BUILD_DIR=$ROOT_DIR/build +export CICD_DIR=$ROOT_DIR/.cicd +export HELPERS_DIR=$CICD_DIR/helpers +export JOBS=${JOBS:-"$(getconf _NPROCESSORS_ONLN)"} +export MOUNTED_DIR='/workdir' diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml new file mode 100644 index 000000000..1d4c3c5e0 --- /dev/null +++ b/.cicd/pipeline.yml @@ -0,0 +1,23 @@ +steps: + + - wait + + - label: ":ubuntu: Ubuntu 18.04 - Build" + command: + - ./.cicd/build.sh + - "tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: $SKIP_UBUNTU_18 + + - wait + + - label: ":ubuntu: Ubuntu 18.04 - Test" + command: + - "buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 18.04 - Build' && tar -xzf build.tar.gz" + - ./.cicd/tests.sh + agents: + queue: "automation-eos-builder-fleet" + timeout: ${TIMEOUT:-10} + skip: $SKIP_UBUNTU_18 \ No newline at end of file diff --git a/.cicd/tests.sh b/.cicd/tests.sh new file mode 100755 index 000000000..29db7c369 --- /dev/null +++ b/.cicd/tests.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail + +. ./.cicd/helpers/general.sh +. ./.cicd/helpers/dependency-info.sh + +mkdir -p $BUILD_DIR + +FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} +ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:$PATH" + +PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" +TEST_COMMANDS="ctest -j $JOBS" + +COMMANDS="$PRE_COMMANDS && $TEST_COMMANDS" + +# Load BUILDKITE Environment Variables for use in docker run +if [[ -f $BUILDKITE_ENV_FILE ]]; then + evars="" + while read -r var; do + evars="$evars --env ${var%%=*}" + done < "$BUILDKITE_ENV_FILE" +fi + +eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..fd9aeb346 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: cpp +git: + depth: false +if: fork = true OR type = api OR type = cron +matrix: + include: + - os: linux + dist: xenial + services: docker +script: "./.cicd/build.sh && ./.cicd/tests.sh" +notifications: + webhooks: + secure: CEIaN/RNCYALwL+QgBhVlyq5DvomyMcmB+gUfdDabxJk55misbIAXkj7l3+1dvq4EeB8Vw3vSKAimfjpj0hGCopOPxPsE5SPYWx3czI7cBPvuu3S4NSmx6WEe+pjI3IexUVQXRLazhvvwB6D/vZnFlr3ECYj59K0fGoYOKW14oG2RLVP7Clx3qoo1O8y7F+Ia6fEp/Q4pvwgFKnUL4hJrCUefJwSKDH8Nxf4FF5U41RLE8Xhdqxo1zbZBpT30gaPERzBnTCO3ko5NIEI/WPruQgcRr/PVDTG1xYZ2XqImDb/fHZKqkOJSoOTH+2U2KBxfXCwLPzkz6CkpJ7v14VL4qoV/F5DA9/fTSB4+B6IWusFF8NhstMmeCw0vkfaO/8WW8VEYHXnlTPFAQZJEiEyIYDcyVnUXur0yFEkvr4ZdGDmUEv/AdClVJ7Ig7T4MF2K66Yqtj930VQhI5PSWMKIWFG+2eboBrmXet+Z+2GRhwCGm5knB4/bcDcg9E80cwUWVol6AxVO07n70Qx57qX9Tvz/Ay9ugtEY+xSDQQ+HkFw62MiPDsNhSFoUD+TNY+SnEe1qnciKhb2/1bNTkKMPjifjJmDWkfC07qrXsDBcj4cIgfj6vh8lBj7U6kg7vCjXeJeljgu0wcTDd+EprDHpfRwkoXi9UsnSw2HXAveZMP4= +env: + global: + secure: jE/hVrQwgGs4KDdBqtiaGb9QE7xg8tn9NK2xMyedsi1CzqSZwl1iLjoefD4nH2wYRCGWfTBFES7QtJbj7SZK0+eobwQMO+jyXSOBd8D8HqcT37UMOPYW72YY2UuZpSCinuLHkZxZnb5dGfMqXDIZ3Y3GIgxOAd2+a0Y6xLt0dfZvh4OH8KVc/wWtuAjh0kMYEoQV9gEyok7xnXNjSLbAbkVslQBKHv451oi8saIGQbFC3b1KSGlE9LBv0QAR9MLXlkYMF3tAfegTGzx/NUIwdOOJ6XoPWoUGWV/u/nWexjHwsb1MwqQHN+LWHRM39ehL46na4m32S/ro3wHmBXnxlF3ys8QH0PEpfJL+r8aKGOv3pmWE//x+Ias6K6RWzTMLRFqlDPGTAGgMRGFiyGhT1aRHXD+mC2RppXptBST9brhE7+lyVqzKYFFHi0SHxfRsSQLgGhIJTMBr2Jj5ORlT86BWdxj3P8VOitKif/RP1zuJBKr78EyLGDPvsJhmot/gPg3VAo2R+cyFqVBWig2PC2ylneSS2DptMV6qLlujA+Fr38diYacsMqhej3ukqVZGaOecSIJXweJQ+7Y9SvGQDeAH8gEzgLLlkNrwpaFtLpxUqHrGWKJHUS8oKtleTznoK1Ck9Es2JTG2Tr4gVHk0OCIfc3hZRQl5Kj7AVi20Tec= \ No newline at end of file diff --git a/pipeline.jsonc b/pipeline.jsonc index 28912b072..846619e3c 100644 --- a/pipeline.jsonc +++ b/pipeline.jsonc @@ -4,8 +4,9 @@ "pipeline-branch": "master", "dependencies": // dependencies to pull for a build of contracts, by branch, tag, or commit hash { - "eosio": "release/1.8.x", - "eosio.cdt": "release/1.6.x" + "eosio": "trav-poc", + "eosio.cdt": "release/1.6.x", + "cdt-version": "1.6.2-1" } } } \ No newline at end of file From f3d718434c2d5bd0a89d93345fe23a32ee56bd47 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 22 Aug 2019 10:29:21 -0400 Subject: [PATCH 035/106] Set pipeline.jsonc to correct values. --- pipeline.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipeline.jsonc b/pipeline.jsonc index 846619e3c..38a145abf 100644 --- a/pipeline.jsonc +++ b/pipeline.jsonc @@ -4,7 +4,7 @@ "pipeline-branch": "master", "dependencies": // dependencies to pull for a build of contracts, by branch, tag, or commit hash { - "eosio": "trav-poc", + "eosio": "release/1.8.x", "eosio.cdt": "release/1.6.x", "cdt-version": "1.6.2-1" } From a64379d4eaa9c2dc3c3be6e4801b449f5e7dec05 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 22 Aug 2019 13:36:12 -0400 Subject: [PATCH 036/106] Escape PATH. --- .cicd/build.sh | 2 +- .cicd/tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index a80c1d9c6..0571e22f1 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -8,7 +8,7 @@ mkdir -p $BUILD_DIR FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:$PATH" +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake .. && make -j $JOBS" diff --git a/.cicd/tests.sh b/.cicd/tests.sh index 29db7c369..2223c5947 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -8,7 +8,7 @@ mkdir -p $BUILD_DIR FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:$PATH" +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" TEST_COMMANDS="ctest -j $JOBS" From 79c607529c8f46c5e22d66a8326e18f4686a9736 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 22 Aug 2019 13:42:03 -0400 Subject: [PATCH 037/106] Escape PATH. --- .cicd/build.sh | 2 +- .cicd/tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 0571e22f1..0d9573aed 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -8,7 +8,7 @@ mkdir -p $BUILD_DIR FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\$PATH" +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake .. && make -j $JOBS" diff --git a/.cicd/tests.sh b/.cicd/tests.sh index 2223c5947..abf0cd0d8 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -8,7 +8,7 @@ mkdir -p $BUILD_DIR FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\$PATH" +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" TEST_COMMANDS="ctest -j $JOBS" From 24257406324b4fce423b471b9d9ee8d2b9e6db67 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 22 Aug 2019 13:54:19 -0400 Subject: [PATCH 038/106] Added test metrics. --- .cicd/metrics/test-metrics.js | 431 ++++++++++++++++++++++++++++++ .cicd/metrics/test-metrics.tar.gz | Bin 0 -> 96551 bytes .cicd/pipeline.yml | 16 +- 3 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 .cicd/metrics/test-metrics.js create mode 100644 .cicd/metrics/test-metrics.tar.gz diff --git a/.cicd/metrics/test-metrics.js b/.cicd/metrics/test-metrics.js new file mode 100644 index 000000000..b995134d9 --- /dev/null +++ b/.cicd/metrics/test-metrics.js @@ -0,0 +1,431 @@ +#!/usr/bin/env node +/* includes */ +const execSync = require('child_process').execSync; // run shell commands +const fetch = require('node-fetch'); // downloading +const fs = require('fs'); // file stream +const XML = require('xml2js'); // parse xml + +/* globals */ +const buildkiteAccessToken = `?access_token=${process.env.BUILDKITE_API_KEY}`; // import buildkite access token from environment +const debug = (process.env.DEBUG === 'true') ? true : false; +let errorCount = 0; // count number of jobs which caused an error +const EXIT_SUCCESS = 0; +const inBuildkite = (process.env.BUILDKITE === 'true') ? true : false; +const outputFile = 'test-metrics.json'; +const pipelineWhitelist = // the pipelines for which we run diagnostics +[ + 'eosio', + 'eosio-base-images', + 'eosio-beta', + 'eosio-build-unpinned', + 'eosio-debug', + 'eosio-lrt', + 'eosio-security' +]; + +/* functions */ +// given a url string, download a text document +async function download(url) +{ + if (debug) console.log(`download(${url.replace(buildkiteAccessToken, '')})`); // DEBUG + const httpResponse = await fetch(url); + const body = await httpResponse.text(); + if (isNullOrEmpty(body)) + { + console.log(`ERROR: URL returned nothing! URL: ${url.replace(buildkiteAccessToken, '')}`); + const error = + { + http: { body, response: httpResponse, url}, + message: 'http body is null or empty', + origin: 'download()', + } + throw error; + } + if (debug) console.log('Download complete.'); // DEBUG + return body; +} + +// given a pipeline and a build number, get a build object +async function getBuild(pipeline, buildNumber) +{ + if (debug) console.log(`getBuild(${pipeline}, ${buildNumber})`); // DEBUG + const httpResponse = await fetch(`https://api.buildkite.com/v2/organizations/EOSIO/pipelines/${pipeline}/builds/${buildNumber}${buildkiteAccessToken}`); + return httpResponse.json(); +} + +// given a buildkite job, return the environmental variables +async function getEnvironment(job) +{ + if (debug) console.log('getEnvironment()'); // DEBUG + const httpResponse = await fetch(`${job.build_url}/jobs/${job.id}/env${buildkiteAccessToken}`); + const environment = await httpResponse.json(); + return environment.env; +} + +// given a string to search, a key as regex or a string, and optionally a start index, return the lowest line number containing the key +function getLineNumber(text, key, startIndex) +{ + if (debug) console.log('getLineNumber()'); // DEBUG + const begin = (isNullOrEmpty(startIndex) || !Number.isInteger(startIndex) || startIndex < 1) ? 0 : startIndex; + let found = false; + let lineNumber = 0; + const regex = (key instanceof RegExp); + text.split('\n').some((line) => + { + if (lineNumber >= begin && ((regex && key.test(line)) || (!regex && line.includes(key)))) + { + found = true; + return true; // c-style break + } + lineNumber += 1; + return false; // for the linter, plz delete when linter is fixed + }); + return (found) ? lineNumber : -1; +} + +// given a buildkite job, return a sanitized log file +async function getLog(job) +{ + if (debug) console.log(`getLog(${job.raw_log_url})`); // DEBUG + const logText = await download(job.raw_log_url + buildkiteAccessToken); + // returns log lowercase, with single spaces and '\n' only, and only ascii-printable characters + return sanitize(logText); // made this a separate function for unit testing purposes +} + +// given a Buildkite environment, return the operating system used +function getOS(environment) +{ + if (debug) console.log(`getOS(${environment.BUILDKITE_LABEL})`); // DEBUG + if (isNullOrEmpty(environment) || isNullOrEmpty(environment.BUILDKITE_LABEL)) + { + console.log('ERROR: getOS() called with empty environment.BUILDKITE_LABEL!'); + console.log(JSON.stringify(environment)); + return null; + } + const label = environment.BUILDKITE_LABEL.toLowerCase(); + if ((/aws(?!.*[23])/.test(label) || /amazon(?!.*[23])/.test(label))) + return 'Amazon Linux 1'; + if (/aws.*2/.test(label) || /amazon.*2/.test(label)) + return 'Amazon Linux 2'; + if (/centos(?!.*[89])/.test(label)) + return 'CentOS 7'; + if (/fedora(?!.*2[89])/.test(label) && /fedora(?!.*3\d)/.test(label)) + return 'Fedora 27'; + if (/high.*sierra/.test(label)) + return 'High Sierra'; + if (/mojave/.test(label)) + return 'Mojave'; + if (/ubuntu.*16.*04/.test(label) || /ubuntu.*16(?!.*10)/.test(label)) + return 'Ubuntu 16.04'; + if (/ubuntu.*18.*04/.test(label) || /ubuntu.*18(?!.*10)/.test(label)) + return 'Ubuntu 18.04'; + if (/docker/.test(label)) + return 'Docker'; + return 'Unknown'; +} + +// given a Buildkite job, return the test-results.xml file as JSON +async function getXML(job) +{ + if (debug) console.log('getXML()'); // DEBUG + const xmlFilename = 'test-results.xml'; + const artifacts = await download(job.artifacts_url + buildkiteAccessToken); + const testResultsArtifact = JSON.parse(artifacts).filter(artifact => artifact.filename === xmlFilename); + if (isNullOrEmpty(testResultsArtifact)) + { + console.log(`WARNING: No ${xmlFilename} found for "${job.name}"! Link: ${job.web_url}`); + return null; + } + const urlBuildkite = testResultsArtifact[0].download_url; + const rawXML = await download(urlBuildkite + buildkiteAccessToken); + const xmlOptions = + { + attrNameProcessors: [function lower(name) { return name.toLowerCase(); }], + explicitArray: false, // do not put single strings in single-element arrays + mergeAttrs: true, // make attributes children of their node + normalizeTags: true, // convert all tag names to lowercase + }; + let xmlError, xmlTestResults; + await XML.parseString(rawXML, xmlOptions, (err, result) => {xmlTestResults = result; xmlError = err;}); + if (isNullOrEmpty(xmlError)) + return xmlTestResults; + console.log(`WARNING: Failed to parse xml for "${job.name}" job! Link: ${job.web_url}`); + console.log(JSON.stringify(xmlError)); + return null; +} + +// test if variable is empty +function isNullOrEmpty(str) +{ + return (str === null || str === undefined || str.length === 0 || /^\s*$/.test(str)); +} + +// return array of test results from a buildkite job log +function parseLog(logText) +{ + if (debug) console.log('parseLog()'); // DEBUG + const lines = logText.split('\n'); + const resultLines = lines.filter(line => /test\s+#\d+/.test(line)); // 'grep' for the test result lines + // parse the strings and make test records + return resultLines.map((line) => + { + const y = line.trim().split(/test\s+#\d+/).pop(); // remove everything before the test declaration + const parts = y.split(/\s+/).slice(1, -1); // split the line and remove the test number and time unit + const testName = parts[0]; + const testTime = parts[(parts.length - 1)]; + const rawResult = parts.slice(1, -1).join(); + let testResult; + if (rawResult.includes('failed')) + testResult = 'Failed'; + else if (rawResult.includes('passed')) + testResult = 'Passed'; + else + testResult = 'Exception'; + return { testName, testResult, testTime }; // create a test record + }); +} + +// return array of test results from an xUnit-formatted JSON object +function parseXunit(xUnit) +{ + if (debug) console.log('parseXunit()'); // DEBUG + if (isNullOrEmpty(xUnit)) + { + console.log('WARNING: xUnit is empty!'); + return null; + } + return xUnit.site.testing.test.map((test) => + { + const testName = test.name; + const testTime = test.results.namedmeasurement.filter(x => /execution\s+time/.test(x.name.toLowerCase()))[0].value; + let testResult; + if (test.status.includes('failed')) + testResult = 'Failed'; + else if (test.status.includes('passed')) + testResult = 'Passed'; + else + testResult = 'Exception'; + return { testName, testResult, testTime }; + }); +} + +// returns text lowercase, with single spaces and '\n' only, and only ascii-printable characters +function sanitize(text) +{ + if (debug) console.log(`sanitize(text) where text.length = ${text.length} bytes`); // DEBUG + const chunkSize = 131072; // process text in 128 kB chunks + if (text.length > chunkSize) + return sanitize(text.slice(0, chunkSize)).concat(sanitize(text.slice(chunkSize))); + return text + .replace(/(?!\n)\r(?!\n)/g, '\n').replace(/\r/g, '') // convert all line endings to '\n' + .replace(/[^\S\n]+/g, ' ') // convert all whitespace to ' ' + .replace(/[^ -~\n]+/g, '') // remove non-printable characters + .toLowerCase(); +} + +// input is array of whole lines containing "test #" and ("failed" or "exception") +function testDiagnostics(test, logText) +{ + if (debug) + { + console.log(`testDiagnostics(test, logText) where logText.length = ${logText.length} bytes and test is`); // DEBUG + console.log(JSON.stringify(test)); + } + // get basic information + const testResultLine = new RegExp(`test\\s+#\\d+.*${test.testName}`, 'g'); // regex defining "test #" line + const startIndex = getLineNumber(logText, testResultLine); + const output = { errorMsg: null, lineNumber: startIndex + 1, stackTrace: null }; // default output + // filter tests + if (test.testResult.toLowerCase() === 'passed') + return output; + output.errorMsg = 'test diangostics are not enabled for this pipeline'; + if (!pipelineWhitelist.includes(test.pipeline)) + return output; + // diagnostics + if (debug) console.log('Running diagnostics...'); // DEBUG + output.errorMsg = 'uncategorized'; + const testLog = logText.split(testResultLine)[1].split(/test\s*#/)[0].split('\n'); // get log output from this test only, as array of lines + let errorLine = testLog[0]; // first line, from "test ## name" to '\n' exclusive + if (/\.+ *\** *not run\s+0+\.0+ sec$/.test(errorLine)) // not run + output.errorMsg = 'test not run'; + else if (/\.+ *\** *time *out\s+\d+\.\d+ sec$/.test(errorLine)) // timeout + output.errorMsg = 'test timeout'; + else if (/exception/.test(errorLine)) // test exception + output.errorMsg = errorLine.split('exception')[1].replace(/[: \d.]/g, '').replace(/sec$/, ''); // isolate the error message after exception + else if (/fc::.*exception/.test(testLog.filter(line => !isNullOrEmpty(line))[1])) // fc exception + { + [, errorLine] = testLog.filter(line => !isNullOrEmpty(line)); // get first line + output.errorMsg = `fc::${errorLine.split('::')[1].replace(/['",]/g, '').split(' ')[0]}`; // isolate fx exception body + } + else if (testLog.join('\n').includes('ctest:')) // ctest exception + { + [errorLine] = testLog.filter(line => line.includes('ctest:')); + output.errorMsg = `ctest:${errorLine.split('ctest:')[1]}`; + } + else if (!isNullOrEmpty(testLog.filter(line => /boost.+exception/.test(line)))) // boost exception + { + [errorLine] = testLog.filter(line => /boost.+exception/.test(line)); + output.errorMsg = `boost: ${errorLine.replace(/[()]/g, '').split(/: (.+)/)[1]}`; // capturing parenthesis, split only at first ' :' + output.stackTrace = testLog.filter(line => /thread-\d+/.test(line))[0].split('thread-')[1].replace(/^\d+/, '').trim().replace(/[[]\d+m$/, ''); // get the bottom of the stack trace + } + else if (/unit[-_. ]+test/.test(test.testName) || /plugin[-_. ]+test/.test(test.testName)) // unit test, application exception + { + if (!isNullOrEmpty(testLog.filter(line => line.includes('exception: ')))) + { + [errorLine] = testLog.filter(line => line.includes('exception: ')); + [, output.errorMsg] = errorLine.replace(/[()]/g, '').split(/: (.+)/); // capturing parenthesis, split only at first ' :' + output.stackTrace = testLog.filter(line => /thread-\d+/.test(line))[0].split('thread-')[1].replace(/^\d+/, '').trim().replace(/[[]\d+m$/, ''); // get the bottom of the stack trace + } + // else uncategorized unit test + } + // else integration test, add cross-referencing code here (or uncategorized) + if (errorLine !== testLog[0]) // get real line number from log file + output.lineNumber = getLineNumber(logText, errorLine, startIndex) + 1; + return output; +} + +// return test metrics given a buildkite job or build +async function testMetrics(buildkiteObject) +{ + if (!isNullOrEmpty(buildkiteObject.type)) // input is a Buildkite job object + { + const job = buildkiteObject; + console.log(`Processing test metrics for "${job.name}"${(inBuildkite) ? '' : ` at ${job.web_url}`}...`); + if (isNullOrEmpty(job.exit_status)) + { + console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}WARNING: "${job.name}" was skipped!`); + return null; + } + // get test results + const logText = await getLog(job); + let testResults; + let xUnit; + try + { + xUnit = await getXML(job); + testResults = parseXunit(xUnit); + } + catch (error) + { + console.log(`XML processing failed for "${job.name}"! Link: ${job.web_url}`); + console.log(JSON.stringify(error)); + testResults = null; + } + finally + { + if (isNullOrEmpty(testResults)) + testResults = parseLog(logText); + } + // get test metrics + const env = await getEnvironment(job); + env.BUILDKITE_REPO = env.BUILDKITE_REPO.replace(new RegExp('^git@github.com:(EOSIO/)?'), '').replace(new RegExp('.git$'), ''); + const metrics = []; + const os = getOS(env); + testResults.forEach((result) => + { + // add test properties + const test = + { + ...result, // add testName, testResult, testTime + agentName: env.BUILDKITE_AGENT_NAME, + agentRole: env.BUILDKITE_AGENT_META_DATA_QUEUE || env.BUILDKITE_AGENT_META_DATA_ROLE, + branch: env.BUILDKITE_BRANCH, + buildNumber: env.BUILDKITE_BUILD_NUMBER, + commit: env.BUILDKITE_COMMIT, + job: env.BUILDKITE_LABEL, + os, + pipeline: env.BUILDKITE_PIPELINE_SLUG, + repo: env.BUILDKITE_REPO, + testTime: parseFloat(result.testTime), + url: job.web_url, + }; + metrics.push({ ...test, ...testDiagnostics(test, logText) }); + }); + return metrics; + } + else if (!isNullOrEmpty(buildkiteObject.number)) // input is a Buildkite build object + { + const build = buildkiteObject; + console.log(`Processing test metrics for ${build.pipeline.slug} build ${build.number}${(inBuildkite) ? '' : ` at ${build.web_url}`}...`); + let metrics = [], promises = []; + // process test metrics + build.jobs.filter(job => job.type === 'script' && /test/.test(job.name.toLowerCase()) && ! /test metrics/.test(job.name.toLowerCase())).forEach((job) => + { + promises.push( + testMetrics(job) + .then((moreMetrics) => { + if (!isNullOrEmpty(moreMetrics)) + metrics = metrics.concat(moreMetrics); + else + console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}WARNING: "${job.name}" metrics are empty!\nmetrics = ${JSON.stringify(moreMetrics)}`); + }).catch((error) => { + console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Failed to process test metrics for "${job.name}"! Link: ${job.web_url}`); + console.log(JSON.stringify(error)); + errorCount++; + }) + ); + }); + await Promise.all(promises); + return metrics; + } + else // something else + { + console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Buildkite object not recognized or not a test step!`); + console.log(JSON.stringify({buildkiteObject})); + return null; + } +} + +/* main */ +async function main() +{ + if (debug) console.log(`$ ${process.argv.join(' ')}`); + let build, metrics = null; + console.log(`${(inBuildkite) ? '+++ :evergreen_tree: ' : ''}Getting information from enviroment...`); + const buildNumber = process.env.BUILDKITE_BUILD_NUMBER || process.argv[2]; + const pipeline = process.env.BUILDKITE_PIPELINE_SLUG || process.argv[3]; + if (debug) + { + console.log(`BUILDKITE=${process.env.BUILDKITE}`); + console.log(`BUILDKITE_BUILD_NUMBER=${process.env.BUILDKITE_BUILD_NUMBER}`); + console.log(`BUILDKITE_PIPELINE_SLUG=${process.env.BUILDKITE_PIPELINE_SLUG}`); + console.log(' State:') + console.log(`inBuildkite = "${inBuildkite}"`); + console.log(`buildNumber = "${buildNumber}"`); + console.log(`pipeline = "${pipeline}"`); + } + if (isNullOrEmpty(buildNumber) || isNullOrEmpty(pipeline) || isNullOrEmpty(process.env.BUILDKITE_API_KEY)) + { + console.log(`${(inBuildkite) ? '+++ :no_entry: ' : ''}ERROR: Missing required inputs!`); + if (isNullOrEmpty(process.env.BUILDKITE_API_KEY)) console.log('- Buildkite API key, as BUILDKITE_API_KEY environment variable'); + if (isNullOrEmpty(buildNumber)) console.log('- Build Number, as BUILDKITE_BUILD_NUMBER or argument 1'); + if (isNullOrEmpty(pipeline)) console.log('- Pipeline Slug, as BUILDKITE_PIPELINE_SLUG or argument 2'); + errorCount = -1; + } + else + { + console.log(`${(inBuildkite) ? '+++ :bar_chart: ' : ''}Processing test metrics...`); + build = await getBuild(pipeline, buildNumber); + metrics = await testMetrics(build); + console.log('Done processing test metrics.'); + } + console.log(`${(inBuildkite) ? '+++ :pencil: ' : ''}Writing to file...`); + fs.writeFileSync(outputFile, JSON.stringify({ metrics })); + console.log(`Saved metrics to "${outputFile}" in "${process.cwd()}".`); + if (inBuildkite) + { + console.log('+++ :arrow_up: Uploading artifact...'); + execSync(`buildkite-agent artifact upload ${outputFile}`); + } + if (errorCount === 0) + console.log(`${(inBuildkite) ? '+++ :white_check_mark: ' : ''}Done!`); + else + { + console.log(`${(inBuildkite) ? '+++ :warning: ' : ''}Finished with errors.`); + console.log(`Please send automation a link to this job${(isNullOrEmpty(build)) ? '.' : `: ${build.web_url}`}`); + console.log('@kj4ezj or @zreyn on Telegram'); + } + return (inBuildkite) ? process.exit(EXIT_SUCCESS) : process.exit(errorCount); +}; + +main(); \ No newline at end of file diff --git a/.cicd/metrics/test-metrics.tar.gz b/.cicd/metrics/test-metrics.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2381787ca06196f1b95c636435a77b58ba1cc0aa GIT binary patch literal 96551 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 Date: Fri, 23 Aug 2019 09:22:16 -0400 Subject: [PATCH 039/106] Fix tagged EOSIO versions and CDT_URL. --- .cicd/build.sh | 2 +- .cicd/helpers/dependency-info.sh | 16 +++++++++------- .cicd/tests.sh | 2 +- pipeline.jsonc | 3 +-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 0d9573aed..c099f344b 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -6,7 +6,7 @@ set -eo pipefail mkdir -p $BUILD_DIR -FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} +FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index 533bf1d5c..ed8e09eb3 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -7,20 +7,22 @@ set -eo pipefail if [[ -f "$RAW_PIPELINE_CONFIG" ]]; then echo 'Reading pipeline configuration file...' cat "$RAW_PIPELINE_CONFIG" | grep -Po '^[^"/]*("((?<=\\).|[^"])*"[^"/]*)*' | jq -c .\"eosio-dot-contracts\" > "$PIPELINE_CONFIG" - EOSIO_BRANCH=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies.eosio') - CDT_BRANCH=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."eosio.cdt"') - CDT_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."cdt-version"') + CDT_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."eosio.cdt"') + EOSIO_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies.eosio') else echo 'ERROR: No pipeline configuration file or dependencies file found!' exit 1 fi if [[ $TRAVIS ]]; then - CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_BRANCH && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_BRANCH) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + EOSIO_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match else - CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_BRANCH && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_BRANCH) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + EOSIO_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match fi test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_BRANCH | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_BRANCH\"..." +test -z "$EOSIO_COMMIT" && EOSIO_COMMIT=$(echo $EOSIO_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already +echo "Using eosio ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\"..." -export BRANCH=$(echo $EOSIO_BRANCH | sed 's/\//\_/') -export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt_${CDT_VERSION}-ubuntu-18.04_amd64.deb" \ No newline at end of file +export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt-ubuntu-18.04_amd64.deb" \ No newline at end of file diff --git a/.cicd/tests.sh b/.cicd/tests.sh index abf0cd0d8..d421f4384 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -6,7 +6,7 @@ set -eo pipefail mkdir -p $BUILD_DIR -FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$BRANCH} +FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" diff --git a/pipeline.jsonc b/pipeline.jsonc index 38a145abf..28912b072 100644 --- a/pipeline.jsonc +++ b/pipeline.jsonc @@ -5,8 +5,7 @@ "dependencies": // dependencies to pull for a build of contracts, by branch, tag, or commit hash { "eosio": "release/1.8.x", - "eosio.cdt": "release/1.6.x", - "cdt-version": "1.6.2-1" + "eosio.cdt": "release/1.6.x" } } } \ No newline at end of file From 18503073ff056e35ade67162376873220065c499 Mon Sep 17 00:00:00 2001 From: arhag Date: Sun, 1 Sep 2019 21:55:29 -0400 Subject: [PATCH 040/106] prevent overflow within claimrewards in cases of extreme inflation; added eosio_system_tests/extreme_inflation test --- contracts/eosio.system/src/producer_pay.cpp | 1 + tests/eosio.system_tests.cpp | 37 +++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index 28ec8f51f..aca711725 100644 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -83,6 +83,7 @@ namespace eosiosystem { if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > time_point() ) { int64_t new_tokens = (_gstate4.continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year); + check( new_tokens >= 0, "overflow in calculating new tokens to be issued; inflation rate is too high" ); int64_t to_producers = (new_tokens * uint128_t(pay_factor_precision)) / _gstate4.inflation_pay_factor; int64_t to_savings = new_tokens - to_producers; diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index e4bca563d..1eed42e40 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -1525,6 +1525,43 @@ BOOST_FIXTURE_TEST_CASE(change_inflation, eosio_system_tester) try { } FC_LOG_AND_RETHROW() +BOOST_AUTO_TEST_CASE(extreme_inflation) try { + eosio_system_tester t(eosio_system_tester::setup_level::minimal); + symbol core_symbol{CORE_SYM}; + t.create_currency( N(eosio.token), config::system_account_name, asset((1ll << 62) - 1, core_symbol) ); + t.issue( asset(10000000000000, core_symbol) ); + t.deploy_contract(); + t.produce_block(); + t.create_account_with_resources(N(defproducera), config::system_account_name, core_sym::from_string("1.0000"), false); + BOOST_REQUIRE_EQUAL(t.success(), t.regproducer(N(defproducera))); + t.transfer( config::system_account_name, "defproducera", core_sym::from_string("200000000.0000"), config::system_account_name); + BOOST_REQUIRE_EQUAL(t.success(), t.stake("defproducera", core_sym::from_string("100000000.0000"), core_sym::from_string("100000000.0000"))); + BOOST_REQUIRE_EQUAL(t.success(), t.vote( N(defproducera), { N(defproducera) })); + t.produce_blocks(4); + t.produce_block(fc::hours(24)); + + BOOST_REQUIRE_EQUAL(t.success(), t.push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); + t.produce_block(); + asset current_supply; + { + vector data = t.get_row_by_account( N(eosio.token), core_symbol.to_symbol_code().value, N(stat), core_symbol.to_symbol_code().value ); + current_supply = t.token_abi_ser.binary_to_variant("currency_stats", data, eosio_system_tester::abi_serializer_max_time)["supply"].template as(); + } + t.issue( asset((1ll << 62) - 1, core_symbol) - current_supply ); + BOOST_REQUIRE_EQUAL(t.success(), t.setinflation(std::numeric_limits::max(), 50000, 40000)); + t.produce_block(); + + t.produce_block(fc::hours(10*24)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("quantity exceeds available supply"), t.push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); + + t.produce_block(fc::hours(11*24)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("magnitude of asset amount must be less than 2^62"), t.push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); + + t.produce_block(fc::hours(24)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("overflow in calculating new tokens to be issued; inflation rate is too high"), t.push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); + BOOST_REQUIRE_EQUAL(t.success(), t.setinflation(500, 50000, 40000)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("quantity exceeds available supply"), t.push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); +} FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try { From 2dcb23e4ee076b9481fc35a0f08344f058587ee2 Mon Sep 17 00:00:00 2001 From: arhag Date: Sun, 1 Sep 2019 23:02:22 -0400 Subject: [PATCH 041/106] handle overflow check properly (avoid undefined behavior) --- contracts/eosio.system/src/producer_pay.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index aca711725..b8403714c 100644 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -82,8 +82,10 @@ namespace eosiosystem { const auto usecs_since_last_fill = (ct - _gstate.last_pervote_bucket_fill).count(); if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > time_point() ) { - int64_t new_tokens = (_gstate4.continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year); - check( new_tokens >= 0, "overflow in calculating new tokens to be issued; inflation rate is too high" ); + double additional_inflation = (_gstate4.continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year); + check( additional_inflation <= double(std::numeric_limits::max() - ((1ll << 10) - 1)), + "overflow in calculating new tokens to be issued; inflation rate is too high" ); + int64_t new_tokens = static_cast(additional_inflation); int64_t to_producers = (new_tokens * uint128_t(pay_factor_precision)) / _gstate4.inflation_pay_factor; int64_t to_savings = new_tokens - to_producers; From cfe029719b9bf185ccaecd3902438dddad05ca34 Mon Sep 17 00:00:00 2001 From: arhag Date: Sun, 1 Sep 2019 23:19:22 -0400 Subject: [PATCH 042/106] ensure floating point math cannot possibly lead to a negative result --- contracts/eosio.system/src/producer_pay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index b8403714c..cf7e2ddeb 100644 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -85,7 +85,7 @@ namespace eosiosystem { double additional_inflation = (_gstate4.continuous_rate * double(token_supply.amount) * double(usecs_since_last_fill)) / double(useconds_per_year); check( additional_inflation <= double(std::numeric_limits::max() - ((1ll << 10) - 1)), "overflow in calculating new tokens to be issued; inflation rate is too high" ); - int64_t new_tokens = static_cast(additional_inflation); + int64_t new_tokens = (additional_inflation < 0.0) ? 0 : static_cast(additional_inflation); int64_t to_producers = (new_tokens * uint128_t(pay_factor_precision)) / _gstate4.inflation_pay_factor; int64_t to_savings = new_tokens - to_producers; From d9791881cb615d59a258d98d1a29f08d3d1a5af9 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Tue, 17 Sep 2019 14:33:45 -0400 Subject: [PATCH 043/106] Fixed issue where builds break when EOS or CDT is specified by commit hash. --- .cicd/helpers/dependency-info.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index f29ac1cb3..1ce31f3da 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -13,16 +13,16 @@ else echo 'ERROR: No pipeline configuration file or dependencies file found!' exit 1 fi +# search GitHub for commit hash by tag and branch, preferring tag if both match if [[ $TRAVIS ]]; then - CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match - EOSIO_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') + EOSIO_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') else - CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match - EOSIO_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | grep -v 'null' | tr -d '"' | sed -n '1p') # search GitHub for commit hash by tag and branch, preferring tag if both match + CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') + EOSIO_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') fi test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_VERSION\"..." test -z "$EOSIO_COMMIT" && EOSIO_COMMIT=$(echo $EOSIO_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already echo "Using eosio ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\"..." - export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt-ubuntu-18.04_amd64.deb" \ No newline at end of file From 9327d606e582fc164ee1fd2c07cc226153077644 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:21:02 -0400 Subject: [PATCH 044/106] Remove empty lines --- .cicd/build.sh | 7 ------- .cicd/pipeline.yml | 1 - .cicd/tests.sh | 7 ------- 3 files changed, 15 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 98d27f1aa..96f3eaa71 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -1,20 +1,14 @@ #!/usr/bin/env bash set -eo pipefail - . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh - mkdir -p $BUILD_DIR - FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" - PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake -DBUILD_TESTS=true .. && make -j $JOBS" - COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" - # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="" @@ -22,5 +16,4 @@ if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi - eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 870ae96c1..ab8bc6d9b 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -1,5 +1,4 @@ steps: - - wait - label: ":ubuntu: Ubuntu 18.04 - Build" diff --git a/.cicd/tests.sh b/.cicd/tests.sh index d421f4384..84115abb5 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -1,20 +1,14 @@ #!/usr/bin/env bash set -eo pipefail - . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh - mkdir -p $BUILD_DIR - FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" - PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" TEST_COMMANDS="ctest -j $JOBS" - COMMANDS="$PRE_COMMANDS && $TEST_COMMANDS" - # Load BUILDKITE Environment Variables for use in docker run if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="" @@ -22,5 +16,4 @@ if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi - eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file From 17322a706f093ba1cd0452a3c5f642eeedf30403 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:22:48 -0400 Subject: [PATCH 045/106] Switch shebang from "#!/usr/bin/env bash" to "#!/bin/bash" for security reasons --- .cicd/build.sh | 2 +- .cicd/helpers/dependency-info.sh | 2 +- .cicd/tests.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 96f3eaa71..39eff4897 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index 1ce31f3da..d24f74b32 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -eo pipefail [[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG="$1" [[ "$RAW_PIPELINE_CONFIG" == '' ]] && export RAW_PIPELINE_CONFIG='pipeline.jsonc' diff --git a/.cicd/tests.sh b/.cicd/tests.sh index 84115abb5..d366fdbda 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh From 1c64d6a9dfd4da87d9f891386a225792cb3ec4ea Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:31:25 -0400 Subject: [PATCH 046/106] Consistent command-step formatting --- .cicd/pipeline.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index ab8bc6d9b..ec851b437 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -2,9 +2,10 @@ steps: - wait - label: ":ubuntu: Ubuntu 18.04 - Build" - command: - - ./.cicd/build.sh - - "tar -pczf build.tar.gz build && buildkite-agent artifact upload build.tar.gz" + command: | + ./.cicd/build.sh + tar -pczf build.tar.gz build + buildkite-agent artifact upload build.tar.gz agents: queue: "automation-eos-builder-fleet" timeout: ${TIMEOUT:-10} @@ -13,9 +14,10 @@ steps: - wait - label: ":ubuntu: Ubuntu 18.04 - Test" - command: - - "buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 18.04 - Build' && tar -xzf build.tar.gz" - - ./.cicd/tests.sh + command: | + buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 18.04 - Build' + tar -xzf build.tar.gz + ./.cicd/tests.sh agents: queue: "automation-eos-builder-fleet" timeout: ${TIMEOUT:-10} From 06e77f3d43703a93a59794baa51f917ef00c366a Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:36:51 -0400 Subject: [PATCH 047/106] Add quotes to Buildkite variables --- .cicd/pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index ec851b437..c20d91d48 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -8,8 +8,8 @@ steps: buildkite-agent artifact upload build.tar.gz agents: queue: "automation-eos-builder-fleet" - timeout: ${TIMEOUT:-10} - skip: $SKIP_UBUNTU_18 + timeout: "${TIMEOUT:-10}" + skip: "$SKIP_UBUNTU_18" - wait @@ -20,8 +20,8 @@ steps: ./.cicd/tests.sh agents: queue: "automation-eos-builder-fleet" - timeout: ${TIMEOUT:-10} - skip: $SKIP_UBUNTU_18 + timeout: "${TIMEOUT:-10}" + skip: "$SKIP_UBUNTU_18" - wait: continue_on_failure: true From 382d99bddce573f7775df98604d5fe514c4eb4a8 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:41:13 -0400 Subject: [PATCH 048/106] Retry "docker pull" to protect against failures due to race conditions with eosio pipeline --- .cicd/build.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.cicd/build.sh b/.cicd/build.sh index 39eff4897..27a2b121b 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -16,4 +16,16 @@ if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi +# retry docker pull to protect against failures due to race conditions with eosio pipeline +INDEX='1' +echo "$ docker pull $FULL_TAG" +while [[ "$(docker pull $FULL_TAG 2>&1 | grep -ice "manifest for $FULL_TAG not found")" != '0' ]]; do + echo "ERROR: Docker image \"$FULL_TAG\" not found for eosio commit ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\""'!' + printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://eos-coverage.s3-us-west-2.amazonaws.com/build-$BUILDKITE_BUILD_NUMBER/code-coverage-report/index.html;content=here\a for this container to exist.\n" + echo "Attempt $INDEX, retry in 60 seconds..." + echo '' + INDEX=$(( $INDEX + 1 )) + sleep 60 +done +# run eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file From 2dc631e3ba5c3e5f525513f49e554367d644bba2 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Wed, 18 Sep 2019 16:58:42 -0400 Subject: [PATCH 049/106] Increase build step timeout from 10 to 40 minutes --- .cicd/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index c20d91d48..4ea9722bb 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -8,7 +8,7 @@ steps: buildkite-agent artifact upload build.tar.gz agents: queue: "automation-eos-builder-fleet" - timeout: "${TIMEOUT:-10}" + timeout: "${TIMEOUT:-40}" skip: "$SKIP_UBUNTU_18" - wait From 2b0adf847fa28a346bc872cd4c14f90738fc83a2 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 10:36:47 -0400 Subject: [PATCH 050/106] Always use the same container to build and test --- .cicd/build.sh | 1 + .cicd/tests.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 27a2b121b..7c99994bb 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -4,6 +4,7 @@ set -eo pipefail . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} +buildkite-agent meta-data set docker-image "$FULL_TAG" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" diff --git a/.cicd/tests.sh b/.cicd/tests.sh index d366fdbda..9f87e59ca 100755 --- a/.cicd/tests.sh +++ b/.cicd/tests.sh @@ -3,7 +3,7 @@ set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR -FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} +FULL_TAG="$(buildkite-agent meta-data get docker-image)" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" From f693dd15018018a44e7c50a7daaf31d200bff1dc Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 10:39:23 -0400 Subject: [PATCH 051/106] Rename tests.sh to test.sh for consistency --- .cicd/pipeline.yml | 2 +- .cicd/{tests.sh => test.sh} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .cicd/{tests.sh => test.sh} (100%) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 4ea9722bb..009fe0ef9 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -17,7 +17,7 @@ steps: command: | buildkite-agent artifact download build.tar.gz . --step ':ubuntu: Ubuntu 18.04 - Build' tar -xzf build.tar.gz - ./.cicd/tests.sh + ./.cicd/test.sh agents: queue: "automation-eos-builder-fleet" timeout: "${TIMEOUT:-10}" diff --git a/.cicd/tests.sh b/.cicd/test.sh similarity index 100% rename from .cicd/tests.sh rename to .cicd/test.sh From f54cecd43e8970add1c4550d542fff875e204af4 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 10:42:04 -0400 Subject: [PATCH 052/106] Rename FULL_TAG to DOCKER_IMAGE for clarity --- .cicd/build.sh | 12 ++++++------ .cicd/test.sh | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 7c99994bb..e2df3a87b 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -3,8 +3,8 @@ set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR -FULL_TAG=${FULL_TAG:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} -buildkite-agent meta-data set docker-image "$FULL_TAG" +DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} +buildkite-agent meta-data set docker-image "$DOCKER_IMAGE" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" @@ -19,9 +19,9 @@ if [[ -f $BUILDKITE_ENV_FILE ]]; then fi # retry docker pull to protect against failures due to race conditions with eosio pipeline INDEX='1' -echo "$ docker pull $FULL_TAG" -while [[ "$(docker pull $FULL_TAG 2>&1 | grep -ice "manifest for $FULL_TAG not found")" != '0' ]]; do - echo "ERROR: Docker image \"$FULL_TAG\" not found for eosio commit ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\""'!' +echo "$ docker pull $DOCKER_IMAGE" +while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMAGE not found")" != '0' ]]; do + echo "ERROR: Docker image \"$DOCKER_IMAGE\" not found for eosio commit ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\""'!' printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://eos-coverage.s3-us-west-2.amazonaws.com/build-$BUILDKITE_BUILD_NUMBER/code-coverage-report/index.html;content=here\a for this container to exist.\n" echo "Attempt $INDEX, retry in 60 seconds..." echo '' @@ -29,4 +29,4 @@ while [[ "$(docker pull $FULL_TAG 2>&1 | grep -ice "manifest for $FULL_TAG not f sleep 60 done # run -eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file +eval docker run $ARGS $evars $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/test.sh b/.cicd/test.sh index 9f87e59ca..4bc918438 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -3,7 +3,7 @@ set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR -FULL_TAG="$(buildkite-agent meta-data get docker-image)" +DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" @@ -16,4 +16,4 @@ if [[ -f $BUILDKITE_ENV_FILE ]]; then evars="$evars --env ${var%%=*}" done < "$BUILDKITE_ENV_FILE" fi -eval docker run $ARGS $evars $FULL_TAG bash -c \"$COMMANDS\" \ No newline at end of file +eval docker run $ARGS $evars $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file From 75b365787434d1d56326941555f5e9126d6306b4 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 10:58:48 -0400 Subject: [PATCH 053/106] Move Buildkite environment loading into function --- .cicd/build.sh | 10 ++-------- .cicd/helpers/buildkite.sh | 11 +++++++++++ .cicd/test.sh | 10 ++-------- 3 files changed, 15 insertions(+), 16 deletions(-) create mode 100755 .cicd/helpers/buildkite.sh diff --git a/.cicd/build.sh b/.cicd/build.sh index e2df3a87b..4a32d65c3 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -1,5 +1,6 @@ #!/bin/bash set -eo pipefail +. ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR @@ -10,13 +11,6 @@ CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dp PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake -DBUILD_TESTS=true .. && make -j $JOBS" COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" -# Load BUILDKITE Environment Variables for use in docker run -if [[ -f $BUILDKITE_ENV_FILE ]]; then - evars="" - while read -r var; do - evars="$evars --env ${var%%=*}" - done < "$BUILDKITE_ENV_FILE" -fi # retry docker pull to protect against failures due to race conditions with eosio pipeline INDEX='1' echo "$ docker pull $DOCKER_IMAGE" @@ -29,4 +23,4 @@ while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMA sleep 60 done # run -eval docker run $ARGS $evars $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file +eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/helpers/buildkite.sh b/.cicd/helpers/buildkite.sh new file mode 100755 index 000000000..1d2eee398 --- /dev/null +++ b/.cicd/helpers/buildkite.sh @@ -0,0 +1,11 @@ +# load buildkite intrinsic environment variables for use in docker run +function buildkite-intrinsics() +{ + BK_ENV='' + if [[ -f $BUILDKITE_ENV_FILE ]]; then + while read -r var; do + BK_ENV="$BK_ENV --env ${var%%=*}" + done < "$BUILDKITE_ENV_FILE" + fi + echo "$BK_ENV" +} \ No newline at end of file diff --git a/.cicd/test.sh b/.cicd/test.sh index 4bc918438..b54d1fac1 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -1,5 +1,6 @@ #!/bin/bash set -eo pipefail +. ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR @@ -9,11 +10,4 @@ CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dp PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" TEST_COMMANDS="ctest -j $JOBS" COMMANDS="$PRE_COMMANDS && $TEST_COMMANDS" -# Load BUILDKITE Environment Variables for use in docker run -if [[ -f $BUILDKITE_ENV_FILE ]]; then - evars="" - while read -r var; do - evars="$evars --env ${var%%=*}" - done < "$BUILDKITE_ENV_FILE" -fi -eval docker run $ARGS $evars $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file +eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file From 4c38cf50d2e852f68f6633b7a558f74e35af894e Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 11:36:03 -0400 Subject: [PATCH 054/106] Remove dependency-info.sh from test.sh --- .cicd/test.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.cicd/test.sh b/.cicd/test.sh index b54d1fac1..836494def 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -2,7 +2,6 @@ set -eo pipefail . ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh -. ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} From 040d54cd06e0b939b917418ef26463bac66e78b9 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 11:43:27 -0400 Subject: [PATCH 055/106] Revert "Remove dependency-info.sh from test.sh" as it is needed for CDT installation This reverts commit a5474d70d270f078308b95aaf2957f255e7ed801. --- .cicd/test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.cicd/test.sh b/.cicd/test.sh index 836494def..b54d1fac1 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -2,6 +2,7 @@ set -eo pipefail . ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh +. ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} From 87ea34055811f1b20378079c0ea62cd1ea2e9c38 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 11:56:50 -0400 Subject: [PATCH 056/106] Fix Buildkite URL in Docker pull retry message --- .cicd/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 4a32d65c3..acc2c4a60 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -16,7 +16,7 @@ INDEX='1' echo "$ docker pull $DOCKER_IMAGE" while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMAGE not found")" != '0' ]]; do echo "ERROR: Docker image \"$DOCKER_IMAGE\" not found for eosio commit ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\""'!' - printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://eos-coverage.s3-us-west-2.amazonaws.com/build-$BUILDKITE_BUILD_NUMBER/code-coverage-report/index.html;content=here\a for this container to exist.\n" + printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://buildkite.com/EOSIO/eosio/builds?commit=$BUILDKITE_COMMIT;content=here\a for this container to exist.\n" echo "Attempt $INDEX, retry in 60 seconds..." echo '' INDEX=$(( $INDEX + 1 )) From f6dc91fba9b93dcc67f77a61f0b887ae63b52b8d Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 13:16:53 -0400 Subject: [PATCH 057/106] Use the EOSIO_COMMIT for the URL, not the BUILDKITE_COMMIT --- .cicd/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index acc2c4a60..721df2c50 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -16,7 +16,7 @@ INDEX='1' echo "$ docker pull $DOCKER_IMAGE" while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMAGE not found")" != '0' ]]; do echo "ERROR: Docker image \"$DOCKER_IMAGE\" not found for eosio commit ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\""'!' - printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://buildkite.com/EOSIO/eosio/builds?commit=$BUILDKITE_COMMIT;content=here\a for this container to exist.\n" + printf "There must be a successful build against ${EOSIO_COMMIT:0:7} \033]1339;url=https://buildkite.com/EOSIO/eosio/builds?commit=$EOSIO_COMMIT;content=here\a for this container to exist.\n" echo "Attempt $INDEX, retry in 60 seconds..." echo '' INDEX=$(( $INDEX + 1 )) From 7a4710c12c0b1b7511fb5e872b55a910b730b6c3 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 13:21:57 -0400 Subject: [PATCH 058/106] Use the same CDT binary for both the build and test step --- .cicd/build.sh | 2 ++ .cicd/test.sh | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 721df2c50..c8519bb6f 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -6,6 +6,8 @@ set -eo pipefail mkdir -p $BUILD_DIR DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} buildkite-agent meta-data set docker-image "$DOCKER_IMAGE" +buildkite-agent meta-data set cdt-url "$CDT_URL" +buildkite-agent meta-data set cdt-version "$CDT_VERSION" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" diff --git a/.cicd/test.sh b/.cicd/test.sh index b54d1fac1..4eaecffaa 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -2,8 +2,9 @@ set -eo pipefail . ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh -. ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR +CDT_URL="$(buildkite-agent meta-data get cdt-url)" +CDT_VERSION="$(buildkite-agent meta-data get cdt-version)" DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" From 3ca5b2609d7c1ee895be8820fd5c3c7e6aeba310 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 15:29:23 -0400 Subject: [PATCH 059/106] Export dependency and Docker information as variables on Travis --- .cicd/build.sh | 12 +++++++++--- .cicd/test.sh | 8 +++++--- .travis.yml | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index c8519bb6f..bf97c186b 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -5,9 +5,15 @@ set -eo pipefail . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} -buildkite-agent meta-data set docker-image "$DOCKER_IMAGE" -buildkite-agent meta-data set cdt-url "$CDT_URL" -buildkite-agent meta-data set cdt-version "$CDT_VERSION" +if [[ "$BUILDKITE" == 'true' ]]; then + buildkite-agent meta-data set cdt-url "$CDT_URL" + buildkite-agent meta-data set cdt-version "$CDT_VERSION" + buildkite-agent meta-data set docker-image "$DOCKER_IMAGE" +else + export CDT_URL + export CDT_VERSION + export DOCKER_IMAGE +fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" diff --git a/.cicd/test.sh b/.cicd/test.sh index 4eaecffaa..521530199 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -3,9 +3,11 @@ set -eo pipefail . ./.cicd/helpers/buildkite.sh . ./.cicd/helpers/general.sh mkdir -p $BUILD_DIR -CDT_URL="$(buildkite-agent meta-data get cdt-url)" -CDT_VERSION="$(buildkite-agent meta-data get cdt-version)" -DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" +if [[ "$BUILDKITE" == 'true' ]]; then + CDT_URL="$(buildkite-agent meta-data get cdt-url)" + CDT_VERSION="$(buildkite-agent meta-data get cdt-version)" + DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" +fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" diff --git a/.travis.yml b/.travis.yml index fd9aeb346..57b617af2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: - os: linux dist: xenial services: docker -script: "./.cicd/build.sh && ./.cicd/tests.sh" +script: ". ./.cicd/build.sh && ./.cicd/tests.sh" notifications: webhooks: secure: CEIaN/RNCYALwL+QgBhVlyq5DvomyMcmB+gUfdDabxJk55misbIAXkj7l3+1dvq4EeB8Vw3vSKAimfjpj0hGCopOPxPsE5SPYWx3czI7cBPvuu3S4NSmx6WEe+pjI3IexUVQXRLazhvvwB6D/vZnFlr3ECYj59K0fGoYOKW14oG2RLVP7Clx3qoo1O8y7F+Ia6fEp/Q4pvwgFKnUL4hJrCUefJwSKDH8Nxf4FF5U41RLE8Xhdqxo1zbZBpT30gaPERzBnTCO3ko5NIEI/WPruQgcRr/PVDTG1xYZ2XqImDb/fHZKqkOJSoOTH+2U2KBxfXCwLPzkz6CkpJ7v14VL4qoV/F5DA9/fTSB4+B6IWusFF8NhstMmeCw0vkfaO/8WW8VEYHXnlTPFAQZJEiEyIYDcyVnUXur0yFEkvr4ZdGDmUEv/AdClVJ7Ig7T4MF2K66Yqtj930VQhI5PSWMKIWFG+2eboBrmXet+Z+2GRhwCGm5knB4/bcDcg9E80cwUWVol6AxVO07n70Qx57qX9Tvz/Ay9ugtEY+xSDQQ+HkFw62MiPDsNhSFoUD+TNY+SnEe1qnciKhb2/1bNTkKMPjifjJmDWkfC07qrXsDBcj4cIgfj6vh8lBj7U6kg7vCjXeJeljgu0wcTDd+EprDHpfRwkoXi9UsnSw2HXAveZMP4= From 839bf289670e52976854bf46b57f704316f06a33 Mon Sep 17 00:00:00 2001 From: Zach Butler Date: Thu, 19 Sep 2019 15:50:03 -0400 Subject: [PATCH 060/106] Fix travis.yml test invocation --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 57b617af2..516355254 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: - os: linux dist: xenial services: docker -script: ". ./.cicd/build.sh && ./.cicd/tests.sh" +script: ". ./.cicd/build.sh && ./.cicd/test.sh" notifications: webhooks: secure: CEIaN/RNCYALwL+QgBhVlyq5DvomyMcmB+gUfdDabxJk55misbIAXkj7l3+1dvq4EeB8Vw3vSKAimfjpj0hGCopOPxPsE5SPYWx3czI7cBPvuu3S4NSmx6WEe+pjI3IexUVQXRLazhvvwB6D/vZnFlr3ECYj59K0fGoYOKW14oG2RLVP7Clx3qoo1O8y7F+Ia6fEp/Q4pvwgFKnUL4hJrCUefJwSKDH8Nxf4FF5U41RLE8Xhdqxo1zbZBpT30gaPERzBnTCO3ko5NIEI/WPruQgcRr/PVDTG1xYZ2XqImDb/fHZKqkOJSoOTH+2U2KBxfXCwLPzkz6CkpJ7v14VL4qoV/F5DA9/fTSB4+B6IWusFF8NhstMmeCw0vkfaO/8WW8VEYHXnlTPFAQZJEiEyIYDcyVnUXur0yFEkvr4ZdGDmUEv/AdClVJ7Ig7T4MF2K66Yqtj930VQhI5PSWMKIWFG+2eboBrmXet+Z+2GRhwCGm5knB4/bcDcg9E80cwUWVol6AxVO07n70Qx57qX9Tvz/Ay9ugtEY+xSDQQ+HkFw62MiPDsNhSFoUD+TNY+SnEe1qnciKhb2/1bNTkKMPjifjJmDWkfC07qrXsDBcj4cIgfj6vh8lBj7U6kg7vCjXeJeljgu0wcTDd+EprDHpfRwkoXi9UsnSw2HXAveZMP4= From 088c00a63cc96adec6999e4aa69f18bcea8aee04 Mon Sep 17 00:00:00 2001 From: arhag Date: Sat, 19 Oct 2019 10:28:20 -0400 Subject: [PATCH 061/106] change pronoun in buyrex Ricardian summary --- contracts/eosio.system/ricardian/eosio.system.contracts.md.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in index 70e1b7cd4..dc938ec0f 100644 --- a/contracts/eosio.system/ricardian/eosio.system.contracts.md.in +++ b/contracts/eosio.system/ricardian/eosio.system.contracts.md.in @@ -75,7 +75,7 @@ icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@ --- spec_version: "0.2.0" title: Buy REX Tokens -summary: '{{nowrap from}} buys REX tokens in exchange for {{nowrap amount}} and his vote stake increases by {{nowrap amount}}' +summary: '{{nowrap from}} buys REX tokens in exchange for {{nowrap amount}} and their vote stake increases by {{nowrap amount}}' icon: @ICON_BASE_URL@/@REX_ICON_URI@ --- From 09ff0ecfb10405978b0dc7f85f031ed3d04a95a2 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 24 Oct 2019 15:07:14 -0400 Subject: [PATCH 062/106] Fix for broken test metrics. --- .cicd/test.sh | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.cicd/test.sh b/.cicd/test.sh index 521530199..2c04626bd 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -11,6 +11,24 @@ fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build/tests" -TEST_COMMANDS="ctest -j $JOBS" +TEST_COMMANDS="ctest -j $JOBS --output-on-failure -T Test" COMMANDS="$PRE_COMMANDS && $TEST_COMMANDS" -eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file +set +e +eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" +EXIT_STATUS=$? +# buildkite +if [[ "$BUILDKITE" == 'true' ]]; then + cd build + # upload artifacts + echo '+++ :arrow_up: Uploading Artifacts' + echo 'Exporting xUnit XML' + mv -f ./tests/Testing/$(ls ./tests/Testing/ | grep '2' | tail -n 1)/Test.xml test-results.xml + echo 'Uploading artifacts' + buildkite-agent artifact upload test-results.xml + echo 'Done uploading artifacts.' +fi +# re-throw +if [[ "$EXIT_STATUS" != 0 ]]; then + echo "Failing due to non-zero exit status from ctest: $EXIT_STATUS" + exit $EXIT_STATUS +fi From a013b9fd0e97487b490e9ac8b9b291e0d98f67c6 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 28 Oct 2019 15:53:52 +0200 Subject: [PATCH 063/106] update documentation and code annotations --- README.md | 20 +- .../include/eosio.msig/eosio.msig.hpp | 7 +- .../include/eosio.system/eosio.system.hpp | 481 +++++------------- .../include/eosio.system/exchange_state.hpp | 2 +- .../include/eosio.system/rex.results.hpp | 27 + .../include/eosio.token/eosio.token.hpp | 45 +- docs.json | 40 ++ docs/02_compile-and-deploy.md | 78 +++ .../01_upgrading-the-eosio.system-contract.md | 211 ++++++++ docs/03_guides/02_how-to-buy-ram.md | 8 + docs/03_guides/03_how-to-stake.md | 8 + docs/03_guides/04_how-to-vote.md | 8 + ...ow-to-create-issue-and-transfer-a-token.md | 126 +++++ ...a-multisig-transaction-with-eosio.msig.md} | 41 +- .../07_how-to-use-eosio.wrap.md} | 0 docs/index.md | 211 ++++++++ 16 files changed, 891 insertions(+), 422 deletions(-) create mode 100644 docs.json create mode 100644 docs/02_compile-and-deploy.md create mode 100644 docs/03_guides/01_upgrading-the-eosio.system-contract.md create mode 100644 docs/03_guides/02_how-to-buy-ram.md create mode 100644 docs/03_guides/03_how-to-stake.md create mode 100644 docs/03_guides/04_how-to-vote.md create mode 100644 docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md rename docs/{eosio.msig.md => 03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md} (89%) rename docs/{eosio.wrap.md => 03_guides/07_how-to-use-eosio.wrap.md} (100%) create mode 100644 docs/index.md diff --git a/README.md b/README.md index 2b759f461..04e491a69 100644 --- a/README.md +++ b/README.md @@ -15,22 +15,10 @@ The following unprivileged contract(s) are also part of the system. * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.2) -* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.1) (optional dependency only needed to build unit tests) - -To build contracts alone: -1. Ensure an appropriate version of eosio.cdt is installed. Installing eosio.cdt from binaries is sufficient. -2. Run the `build.sh` script in the top directory to build all the contracts. - -To build the contracts and unit tests: -1. Ensure an appropriate version of eosio.cdt is installed. Installing eosio.cdt from binaries is sufficient. -2. Ensure an appropriate version of eosio has been built from source and installed. Installing eosio from binaries is not sufficient. -3. Run the `build.sh` script in the top directory with the `-t` flag to build all the contracts and the unit tests for these contracts. - -After build: -* If the build was configured to also build unit tests, the unit tests executable is placed in the _build/tests_ folder and is named __unit_test__. -* The contracts (both `.wasm` and `.abi` files) are built into their corresponding _build/contracts/\_ folder. -* Finally, simply use __cleos__ to _set contract_ by pointing to the previously mentioned directory for the specific contract. +* [eosio.cdt v1.7.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.7.0-rc1) +* [eosio v2.0.x](https://github.com/EOSIO/eos/releases/tag/v2.0.0-rc1) (optional dependency only needed to build unit tests) + +To build the contracts follow the instructions in [`Compile and deploy` section](./docs/02_compile-and-deploy.md). ## Contributing diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index cd9237349..465433ec0 100644 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -6,6 +6,7 @@ #include namespace eosio { + /** * @defgroup eosiomsig eosio.msig * @ingroup eosiocontracts @@ -27,8 +28,7 @@ namespace eosio { * authorized by the provided keys and permissions, and if the proposal name doesn’t * already exist; if all validations pass the `proposal_name` and `trx` trasanction are * saved in the proposals table and the `requested` permission levels to the - * approvals table (for the `proposer` context). - * Storage changes are billed to `proposer`. + * approvals table (for the `proposer` context). Storage changes are billed to `proposer`. * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be unique for proposer) @@ -46,8 +46,7 @@ namespace eosio { * proposed by `proposer`. If the proposal's requested approval list contains the `level` * permission then the `level` permission is moved from internal `requested_approvals` list to * internal `provided_approvals` list of the proposal, thus persisting the approval for - * the `proposal_name` proposal. - * Storage changes are billed to `proposer`. + * the `proposal_name` proposal. Storage changes are billed to `proposer`. * * @param proposer - The account proposing a transaction * @param proposal_name - The name of the proposal (should be unique for proposer) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index e42f72c87..fa567ec0e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include #include @@ -75,9 +77,6 @@ namespace eosiosystem { static constexpr int64_t default_votepay_factor = 40000; // per-block pay share = 10000 / 40000 = 25% of the producer pay /** - * - * @defgroup eosiosystem eosio.system - * @ingroup eosiocontracts * eosio.system contract defines the structures and actions needed for blockchain's core functionality. * - Users can stake tokens for CPU and Network bandwidth, and then vote for producers or * delegate their vote to a proxy. @@ -89,15 +88,11 @@ namespace eosiosystem { * @{ */ - /** - * A name bid. - * - * @details A name bid consists of: - * - a `newname` name that the bid is for - * - a `high_bidder` account name that is the one with the highest bid so far - * - the `high_bid` which is amount of highest bid - * - and `last_bid_time` which is the time of the highest bid - */ + // A name bid, which consists of: + // - a `newname` name that the bid is for + // - a `high_bidder` account name that is the one with the highest bid so far + // - the `high_bid` which is amount of highest bid + // - and `last_bid_time` which is the time of the highest bid struct [[eosio::table, eosio::contract("eosio.system")]] name_bid { name newname; name high_bidder; @@ -108,39 +103,22 @@ namespace eosiosystem { uint64_t by_high_bid()const { return static_cast(-high_bid); } }; - /** - * A bid refund. - * - * @details A bid refund is defined by: - * - the `bidder` account name owning the refund - * - the `amount` to be refunded - */ + // A bid refund, which is defined by: + // - the `bidder` account name owning the refund + // - the `amount` to be refunded struct [[eosio::table, eosio::contract("eosio.system")]] bid_refund { name bidder; asset amount; uint64_t primary_key()const { return bidder.value; } }; - - /** - * Name bid table - * - * @details The name bid table is storing all the `name_bid`s instances. - */ typedef eosio::multi_index< "namebids"_n, name_bid, indexed_by<"highbid"_n, const_mem_fun > > name_bid_table; - /** - * Bid refund table. - * - * @details The bid refund table is storing all the `bid_refund`s instances. - */ typedef eosio::multi_index< "bidrefunds"_n, bid_refund > bid_refund_table; - /** - * Defines new global state parameters. - */ + // Defines new global state parameters. struct [[eosio::table("global"), eosio::contract("eosio.system")]] eosio_global_state : eosio::blockchain_parameters { uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } @@ -167,9 +145,7 @@ namespace eosiosystem { (last_producer_schedule_size)(total_producer_vote_weight)(last_name_close) ) }; - /** - * Defines new global state parameters added after version 1.0 - */ + // Defines new global state parameters added after version 1.0 struct [[eosio::table("global2"), eosio::contract("eosio.system")]] eosio_global_state2 { eosio_global_state2(){} @@ -183,9 +159,7 @@ namespace eosiosystem { (total_producer_votepay_share)(revision) ) }; - /** - * Defines new global state parameters added after version 1.3.0 - */ + // Defines new global state parameters added after version 1.3.0 struct [[eosio::table("global3"), eosio::contract("eosio.system")]] eosio_global_state3 { eosio_global_state3() { } time_point last_vpay_state_update; @@ -194,9 +168,7 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state3, (last_vpay_state_update)(total_vpay_share_change_rate) ) }; - /** - * Defines new global state parameters to store inflation rate and distribution - */ + // Defines new global state parameters to store inflation rate and distribution struct [[eosio::table("global4"), eosio::contract("eosio.system")]] eosio_global_state4 { eosio_global_state4() { } double continuous_rate; @@ -206,32 +178,29 @@ namespace eosiosystem { EOSLIB_SERIALIZE( eosio_global_state4, (continuous_rate)(inflation_pay_factor)(votepay_factor) ) }; - /** - * Defines `producer_info` structure to be stored in `producer_info` table, added after version 1.0 - */ + // Defines `producer_info` structure to be stored in `producer_info` table, added after version 1.0 struct [[eosio::table, eosio::contract("eosio.system")]] producer_info { - name owner; - double total_votes = 0; - eosio::public_key producer_key; /// a packed public key object - bool is_active = true; - std::string url; - uint32_t unpaid_blocks = 0; - time_point last_claim_time; - uint16_t location = 0; + name owner; + double total_votes = 0; + eosio::public_key producer_key; /// a packed public key object + bool is_active = true; + std::string url; + uint32_t unpaid_blocks = 0; + time_point last_claim_time; + uint16_t location = 0; + eosio::binary_extension producer_authority; // added in version 1.9.0 uint64_t primary_key()const { return owner.value; } double by_votes()const { return is_active ? -total_votes : total_votes; } bool active()const { return is_active; } - void deactivate() { producer_key = public_key(); is_active = false; } + void deactivate() { producer_key = public_key(); producer_authority.reset(); is_active = false; } // explicit serialization macro is not necessary, used here only to improve compilation time EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) - (unpaid_blocks)(last_claim_time)(location) ) + (unpaid_blocks)(last_claim_time)(location)(producer_authority) ) }; - /** - * Defines new producer info structure to be stored in new producer info table, added after version 1.3.0 - */ + // Defines new producer info structure to be stored in new producer info table, added after version 1.3.0 struct [[eosio::table, eosio::contract("eosio.system")]] producer_info2 { name owner; double votepay_share = 0; @@ -243,32 +212,23 @@ namespace eosiosystem { EOSLIB_SERIALIZE( producer_info2, (owner)(votepay_share)(last_votepay_share_update) ) }; - /** - * Voter info. - * - * @details Voter info stores information about the voter: - * - `owner` the voter - * - `proxy` the proxy set by the voter, if any - * - `producers` the producers approved by this voter if no proxy set - * - `staked` the amount staked - */ + // Voter info. Voter info stores information about the voter: + // - `owner` the voter + // - `proxy` the proxy set by the voter, if any + // - `producers` the producers approved by this voter if no proxy set + // - `staked` the amount staked struct [[eosio::table, eosio::contract("eosio.system")]] voter_info { name owner; /// the voter name proxy; /// the proxy set by the voter, if any std::vector producers; /// the producers approved by this voter if no proxy set int64_t staked = 0; - /** - * Every time a vote is cast we must first "undo" the last vote weight, before casting the - * new vote weight. Vote weight is calculated as: - * - * stated.amount * 2 ^ ( weeks_since_launch/weeks_per_year) - */ + // Every time a vote is cast we must first "undo" the last vote weight, before casting the + // new vote weight. Vote weight is calculated as: + // stated.amount * 2 ^ ( weeks_since_launch/weeks_per_year) double last_vote_weight = 0; /// the vote weight cast the last time the vote was updated - /** - * Total vote weight delegated to this voter. - */ + // Total vote weight delegated to this voter. double proxied_vote_weight= 0; /// the total vote weight delegated to this voter as a proxy bool is_proxy = 0; /// whether the voter is a proxy for others @@ -289,40 +249,23 @@ namespace eosiosystem { EOSLIB_SERIALIZE( voter_info, (owner)(proxy)(producers)(staked)(last_vote_weight)(proxied_vote_weight)(is_proxy)(flags1)(reserved2)(reserved3) ) }; - /** - * Voters table - * - * @details The voters table stores all the `voter_info`s instances, all voters information. - */ + typedef eosio::multi_index< "voters"_n, voter_info > voters_table; - /** - * Defines producer info table added in version 1.0 - */ typedef eosio::multi_index< "producers"_n, producer_info, indexed_by<"prototalvote"_n, const_mem_fun > > producers_table; - /** - * Defines new producer info table added in version 1.3.0 - */ + typedef eosio::multi_index< "producers2"_n, producer_info2 > producers_table2; - /** - * Global state singleton added in version 1.0 - */ + typedef eosio::singleton< "global"_n, eosio_global_state > global_state_singleton; - /** - * Global state singleton added in version 1.1.0 - */ + typedef eosio::singleton< "global2"_n, eosio_global_state2 > global_state2_singleton; - /** - * Global state singleton added in version 1.3 - */ + typedef eosio::singleton< "global3"_n, eosio_global_state3 > global_state3_singleton; - /** - * Global state singleton added in version 1.6.x - */ + typedef eosio::singleton< "global4"_n, eosio_global_state4 > global_state4_singleton; struct [[eosio::table, eosio::contract("eosio.system")]] user_resources { @@ -338,9 +281,7 @@ namespace eosiosystem { EOSLIB_SERIALIZE( user_resources, (owner)(net_weight)(cpu_weight)(ram_bytes) ) }; - /** - * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. - */ + // Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. struct [[eosio::table, eosio::contract("eosio.system")]] delegated_bandwidth { name from; name to; @@ -368,27 +309,20 @@ namespace eosiosystem { EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_amount) ) }; - /** - * These tables are designed to be constructed in the scope of the relevant user, this - * facilitates simpler API for per-user queries - */ + typedef eosio::multi_index< "userres"_n, user_resources > user_resources_table; typedef eosio::multi_index< "delband"_n, delegated_bandwidth > del_bandwidth_table; typedef eosio::multi_index< "refunds"_n, refund_request > refunds_table; - /** - * `rex_pool` structure underlying the rex pool table. - * - * @details A rex pool table entry is defined by: - * - `version` defaulted to zero, - * - `total_lent` total amount of CORE_SYMBOL in open rex_loans - * - `total_unlent` total amount of CORE_SYMBOL available to be lent (connector), - * - `total_rent` fees received in exchange for lent (connector), - * - `total_lendable` total amount of CORE_SYMBOL that have been lent (total_unlent + total_lent), - * - `total_rex` total number of REX shares allocated to contributors to total_lendable, - * - `namebid_proceeds` the amount of CORE_SYMBOL to be transferred from namebids to REX pool, - * - `loan_num` increments with each new loan. - */ + // `rex_pool` structure underlying the rex pool table. A rex pool table entry is defined by: + // - `version` defaulted to zero, + // - `total_lent` total amount of CORE_SYMBOL in open rex_loans + // - `total_unlent` total amount of CORE_SYMBOL available to be lent (connector), + // - `total_rent` fees received in exchange for lent (connector), + // - `total_lendable` total amount of CORE_SYMBOL that have been lent (total_unlent + total_lent), + // - `total_rex` total number of REX shares allocated to contributors to total_lendable, + // - `namebid_proceeds` the amount of CORE_SYMBOL to be transferred from namebids to REX pool, + // - `loan_num` increments with each new loan struct [[eosio::table,eosio::contract("eosio.system")]] rex_pool { uint8_t version = 0; asset total_lent; @@ -402,22 +336,12 @@ namespace eosiosystem { uint64_t primary_key()const { return 0; } }; - /** - * Rex pool table - * - * @details The rex pool table is storing the only one instance of rex_pool which it stores - * the global state of the REX system. - */ typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; - /** - * `rex_fund` structure underlying the rex fund table. - * - * @details A rex fund table entry is defined by: - * - `version` defaulted to zero, - * - `owner` the owner of the rex fund, - * - `balance` the balance of the fund. - */ + // `rex_fund` structure underlying the rex fund table. A rex fund table entry is defined by: + // - `version` defaulted to zero, + // - `owner` the owner of the rex fund, + // - `balance` the balance of the fund. struct [[eosio::table,eosio::contract("eosio.system")]] rex_fund { uint8_t version = 0; name owner; @@ -426,23 +350,14 @@ namespace eosiosystem { uint64_t primary_key()const { return owner.value; } }; - /** - * Rex fund table - * - * @details The rex fund table is storing all the `rex_fund`s instances. - */ typedef eosio::multi_index< "rexfund"_n, rex_fund > rex_fund_table; - /** - * `rex_balance` structure underlying the rex balance table. - * - * @details A rex balance table entry is defined by: - * - `version` defaulted to zero, - * - `owner` the owner of the rex fund, - * - `vote_stake` the amount of CORE_SYMBOL currently included in owner's vote, - * - `rex_balance` the amount of REX owned by owner, - * - `matured_rex` matured REX available for selling. - */ + // `rex_balance` structure underlying the rex balance table. A rex balance table entry is defined by: + // - `version` defaulted to zero, + // - `owner` the owner of the rex fund, + // - `vote_stake` the amount of CORE_SYMBOL currently included in owner's vote, + // - `rex_balance` the amount of REX owned by owner, + // - `matured_rex` matured REX available for selling struct [[eosio::table,eosio::contract("eosio.system")]] rex_balance { uint8_t version = 0; name owner; @@ -454,27 +369,18 @@ namespace eosiosystem { uint64_t primary_key()const { return owner.value; } }; - /** - * Rex balance table - * - * @details The rex balance table is storing all the `rex_balance`s instances. - */ typedef eosio::multi_index< "rexbal"_n, rex_balance > rex_balance_table; - /** - * `rex_loan` structure underlying the `rex_cpu_loan_table` and `rex_net_loan_table`. - * - * @details A rex net/cpu loan table entry is defined by: - * - `version` defaulted to zero, - * - `from` account creating and paying for loan, - * - `receiver` account receiving rented resources, - * - `payment` SYS tokens paid for the loan, - * - `balance` is the amount of SYS tokens available to be used for loan auto-renewal, - * - `total_staked` total amount staked, - * - `loan_num` loan number/id, - * - `expiration` the expiration time when loan will be either closed or renewed - * If payment <= balance, the loan is renewed, and closed otherwise. - */ + // `rex_loan` structure underlying the `rex_cpu_loan_table` and `rex_net_loan_table`. A rex net/cpu loan table entry is defined by: + // - `version` defaulted to zero, + // - `from` account creating and paying for loan, + // - `receiver` account receiving rented resources, + // - `payment` SYS tokens paid for the loan, + // - `balance` is the amount of SYS tokens available to be used for loan auto-renewal, + // - `total_staked` total amount staked, + // - `loan_num` loan number/id, + // - `expiration` the expiration time when loan will be either closed or renewed + // If payment <= balance, the loan is renewed, and closed otherwise. struct [[eosio::table,eosio::contract("eosio.system")]] rex_loan { uint8_t version = 0; name from; @@ -490,21 +396,11 @@ namespace eosiosystem { uint64_t by_owner()const { return from.value; } }; - /** - * Rex cpu loan table - * - * @details The rex cpu loan table is storing all the `rex_loan`s instances for cpu, indexed by loan number, expiration and owner. - */ typedef eosio::multi_index< "cpuloan"_n, rex_loan, indexed_by<"byexpr"_n, const_mem_fun>, indexed_by<"byowner"_n, const_mem_fun> > rex_cpu_loan_table; - /** - * Rex net loan table - * - * @details The rex net loan table is storing all the `rex_loan`s instances for net, indexed by loan number, expiration and owner. - */ typedef eosio::multi_index< "netloan"_n, rex_loan, indexed_by<"byexpr"_n, const_mem_fun>, indexed_by<"byowner"_n, const_mem_fun> @@ -524,11 +420,6 @@ namespace eosiosystem { uint64_t by_time()const { return is_open ? order_time.elapsed.count() : std::numeric_limits::max(); } }; - /** - * Rex order table - * - * @details The rex order table is storing all the `rex_order`s instances, indexed by owner and time and owner. - */ typedef eosio::multi_index< "rexqueue"_n, rex_order, indexed_by<"bytime"_n, const_mem_fun>> rex_order_table; @@ -539,9 +430,7 @@ namespace eosiosystem { }; /** - * The EOSIO system contract. - * - * @details The EOSIO system contract governs ram market, voters, producers, global state. + * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. */ class [[eosio::contract("eosio.system")]] system_contract : public native { @@ -579,15 +468,6 @@ namespace eosiosystem { static constexpr symbol ram_symbol = symbol(symbol_code("RAM"), 0); static constexpr symbol rex_symbol = symbol(symbol_code("REX"), 4); - /** - * System contract constructor. - * - * @details Constructs a system contract based on self account, code account and data. - * - * @param s - The current code account that is executing the action, - * @param code - The original code account that executed the action, - * @param ds - The contract data represented as an `eosio::datastream`. - */ system_contract( name s, name code, datastream ds ); ~system_contract(); @@ -604,9 +484,7 @@ namespace eosiosystem { // Actions: /** - * Init action. - * - * @details Init action initializes the system contract for a version and a symbol. + * The Init action initializes the system contract for a version and a symbol. * Only succeeds when: * - version is 0 and * - symbol is found and @@ -620,9 +498,7 @@ namespace eosiosystem { void init( unsigned_int version, const symbol& core ); /** - * On block action. - * - * @details This special action is triggered when a block is applied by the given producer + * On block action. This special action is triggered when a block is applied by the given producer * and cannot be generated from any other source. It is used to pay producers and calculate * missed blocks of other producers. Producer pay is deposited into the producer's stake * balance and can be withdrawn over time. If blocknum is the start of a new round this may @@ -634,9 +510,7 @@ namespace eosiosystem { void onblock( ignore header ); /** - * Set account limits action. - * - * @details Set the resource limits of an account + * Set account limits action 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, @@ -647,9 +521,7 @@ namespace eosiosystem { void setalimits( const name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight ); /** - * Set account RAM limits action. - * - * @details Set the RAM limits of an account + * Set account RAM limits action, which sets the RAM limits of an account * * @param account - name of the account whose resource limit to be set, * @param ram_bytes - ram limit in absolute bytes. @@ -658,9 +530,7 @@ namespace eosiosystem { void setacctram( const name& account, const std::optional& ram_bytes ); /** - * Set account NET limits action. - * - * @details Set the NET limits of an account + * Set account NET limits action, which sets the NET limits of an account * * @param account - name of the account whose resource limit to be set, * @param net_weight - fractionally proportionate net limit of available resources based on (weight / total_weight_of_all_accounts). @@ -669,9 +539,7 @@ namespace eosiosystem { void setacctnet( const name& account, const std::optional& net_weight ); /** - * Set account CPU limits action. - * - * @details Set the CPU limits of an account + * Set account CPU limits action, which sets the CPU limits of an account * * @param account - name of the account whose resource limit to be set, * @param cpu_weight - fractionally proportionate cpu limit of available resources based on (weight / total_weight_of_all_accounts). @@ -681,9 +549,7 @@ namespace eosiosystem { /** - * Activates a protocol feature. - * - * @details Activates a protocol feature + * Activates a protocol feature * * @param feature_digest - hash of the protocol feature to activate. */ @@ -693,9 +559,7 @@ namespace eosiosystem { // functions defined in delegate_bandwidth.cpp /** - * Delegate bandwidth and/or cpu action. - * - * @details Stakes SYS from the balance of `from` for the benefit of `receiver`. + * Delegate bandwidth and/or cpu action. Stakes SYS from the balance of `from` for the benefit of `receiver`. * * @param from - the account to delegate bandwidth from, that is, the account holding * tokens to be staked, @@ -721,9 +585,7 @@ namespace eosiosystem { void setrex( const asset& balance ); /** - * Deposit to REX fund action. - * - * @details Deposits core tokens to user REX fund. + * Deposit to REX fund action. Deposits core tokens to user REX fund. * All proceeds and expenses related to REX are added to or taken out of this fund. * An inline transfer from 'owner' liquid balance is executed. * All REX-related costs and proceeds are deducted from and added to 'owner' REX fund, @@ -749,9 +611,7 @@ namespace eosiosystem { void withdraw( const name& owner, const asset& amount ); /** - * Buyrex action. - * - * @details Buys REX in exchange for tokens taken out of user's REX fund by transfering + * Buyrex action. Buys REX in exchange for tokens taken out of user's REX fund by transfering * core tokens from user REX fund and converts them to REX stake. By buying REX, user is * lending tokens in order to be rented as CPU or NET resourses. * Storage change is billed to 'from' account. @@ -770,9 +630,7 @@ namespace eosiosystem { void buyrex( const name& from, const asset& amount ); /** - * Unstaketorex action. - * - * @details Use staked core tokens to buy REX. + * Unstaketorex action. Use staked core tokens to buy REX. * Storage change is billed to 'owner' account. * * @param owner - owner of staked tokens, @@ -791,9 +649,7 @@ namespace eosiosystem { void unstaketorex( const name& owner, const name& receiver, const asset& from_net, const asset& from_cpu ); /** - * Sellrex action. - * - * @details Sells REX in exchange for core tokens by converting REX stake back into core tokens + * Sellrex action. Sells REX in exchange for core tokens by converting REX stake back into core tokens * at current exchange rate. If order cannot be processed, it gets queued until there is enough * in REX pool to fill order, and will be processed within 30 days at most. If successful, user * votes are updated, that is, proceeds are deducted from user's voting power. In case sell order @@ -806,9 +662,7 @@ namespace eosiosystem { void sellrex( const name& from, const asset& rex ); /** - * Cnclrexorder action. - * - * @details Cancels unfilled REX sell order by owner if one exists. + * Cnclrexorder action. Cancels unfilled REX sell order by owner if one exists. * * @param owner - owner account name. * @@ -818,9 +672,7 @@ namespace eosiosystem { void cnclrexorder( const name& owner ); /** - * Rentcpu action. - * - * @details Use payment to rent as many SYS tokens as possible as determined by market price and + * Rentcpu action. Use payment to rent as many SYS tokens as possible as determined by market price and * stake them for CPU for the benefit of receiver, after 30 days the rented core delegation of CPU * will expire. At expiration, if balance is greater than or equal to `loan_payment`, `loan_payment` * is taken out of loan balance and used to renew the loan. Otherwise, the loan is closed and user @@ -840,9 +692,7 @@ namespace eosiosystem { void rentcpu( const name& from, const name& receiver, const asset& loan_payment, const asset& loan_fund ); /** - * Rentnet action. - * - * @details Use payment to rent as many SYS tokens as possible as determined by market price and + * Rentnet action. Use payment to rent as many SYS tokens as possible as determined by market price and * stake them for NET for the benefit of receiver, after 30 days the rented core delegation of NET * will expire. At expiration, if balance is greater than or equal to `loan_payment`, `loan_payment` * is taken out of loan balance and used to renew the loan. Otherwise, the loan is closed and user @@ -862,9 +712,7 @@ namespace eosiosystem { void rentnet( const name& from, const name& receiver, const asset& loan_payment, const asset& loan_fund ); /** - * Fundcpuloan action. - * - * @details Transfers tokens from REX fund to the fund of a specific CPU loan in order to + * Fundcpuloan action. Transfers tokens from REX fund to the fund of a specific CPU loan in order to * be used for loan renewal at expiry. * * @param from - loan creator account, @@ -875,9 +723,7 @@ namespace eosiosystem { void fundcpuloan( const name& from, uint64_t loan_num, const asset& payment ); /** - * Fundnetloan action. - * - * @details Transfers tokens from REX fund to the fund of a specific NET loan in order to + * Fundnetloan action. Transfers tokens from REX fund to the fund of a specific NET loan in order to * be used for loan renewal at expiry. * * @param from - loan creator account, @@ -888,9 +734,7 @@ namespace eosiosystem { void fundnetloan( const name& from, uint64_t loan_num, const asset& payment ); /** - * Defcpuloan action. - * - * @details Withdraws tokens from the fund of a specific CPU loan and adds them to REX fund. + * Defcpuloan action. Withdraws tokens from the fund of a specific CPU loan and adds them to REX fund. * * @param from - loan creator account, * @param loan_num - loan id, @@ -900,9 +744,7 @@ namespace eosiosystem { void defcpuloan( const name& from, uint64_t loan_num, const asset& amount ); /** - * Defnetloan action. - * - * @details Withdraws tokens from the fund of a specific NET loan and adds them to REX fund. + * Defnetloan action. Withdraws tokens from the fund of a specific NET loan and adds them to REX fund. * * @param from - loan creator account, * @param loan_num - loan id, @@ -912,9 +754,7 @@ namespace eosiosystem { void defnetloan( const name& from, uint64_t loan_num, const asset& amount ); /** - * Updaterex action. - * - * @details Updates REX owner vote weight to current value of held REX tokens. + * Updaterex action. Updates REX owner vote weight to current value of held REX tokens. * * @param owner - REX owner account. */ @@ -922,9 +762,7 @@ namespace eosiosystem { void updaterex( const name& owner ); /** - * Rexexec action. - * - * @details Processes max CPU loans, max NET loans, and max queued sellrex orders. + * Rexexec action. Processes max CPU loans, max NET loans, and max queued sellrex orders. * Action does not execute anything related to a specific user. * * @param user - any account can execute this action, @@ -934,9 +772,7 @@ namespace eosiosystem { void rexexec( const name& user, uint16_t max ); /** - * Consolidate action. - * - * @details Consolidates REX maturity buckets into one bucket that can be sold after 4 days + * Consolidate action. Consolidates REX maturity buckets into one bucket that can be sold after 4 days * starting from the end of the day. * * @param owner - REX owner account name. @@ -945,9 +781,7 @@ namespace eosiosystem { void consolidate( const name& owner ); /** - * Mvtosavings action. - * - * @details Moves a specified amount of REX into savings bucket. REX savings bucket + * Mvtosavings action. Moves a specified amount of REX into savings bucket. REX savings bucket * never matures. In order for it to be sold, it has to be moved explicitly * out of that bucket. Then the moved amount will have the regular maturity * period of 4 days starting from the end of the day. @@ -959,9 +793,7 @@ namespace eosiosystem { void mvtosavings( const name& owner, const asset& rex ); /** - * Mvfrsavings action. - * - * @details Moves a specified amount of REX out of savings bucket. The moved amount + * Mvfrsavings action. Moves a specified amount of REX out of savings bucket. The moved amount * will have the regular REX maturity period of 4 days. * * @param owner - REX owner account name. @@ -971,9 +803,7 @@ namespace eosiosystem { void mvfrsavings( const name& owner, const asset& rex ); /** - * Closerex action. - * - * @details Deletes owner records from REX tables and frees used RAM. Owner must not have + * Closerex action. Deletes owner records from REX tables and frees used RAM. Owner must not have * an outstanding REX balance. * * @param owner - user account name. @@ -987,9 +817,7 @@ namespace eosiosystem { void closerex( const name& owner ); /** - * Undelegate bandwitdh action. - * - * @details Decreases the total tokens delegated by `from` to `receiver` and/or + * Undelegate bandwitdh action. Decreases the total tokens delegated by `from` to `receiver` and/or * frees the memory associated with the delegation if there is nothing * left to delegate. * This will cause an immediate reduction in net/cpu bandwidth of the @@ -1020,9 +848,7 @@ namespace eosiosystem { const asset& unstake_net_quantity, const asset& unstake_cpu_quantity ); /** - * Buy ram action. - * - * @details Increases receiver's ram quota based upon current price and quantity of + * Buy ram action. Increases receiver's ram quota based upon current price and quantity of * tokens provided. An inline transfer from receiver to system contract of * tokens will be executed. * @@ -1034,9 +860,7 @@ namespace eosiosystem { void buyram( const name& payer, const name& receiver, const asset& quant ); /** - * Buy a specific amount of ram bytes action. - * - * @details Increases receiver's ram in quantity of bytes provided. + * Buy a specific amount of ram bytes action. Increases receiver's ram in quantity of bytes provided. * An inline transfer from receiver to system contract of tokens will be executed. * * @param payer - the ram buyer, @@ -1047,9 +871,7 @@ namespace eosiosystem { void buyrambytes( const name& payer, const name& receiver, uint32_t bytes ); /** - * Sell ram action. - * - * @details Reduces quota by bytes and then performs an inline transfer of tokens + * Sell ram action. Reduces quota by bytes and then performs an inline transfer of tokens * to receiver based upon the average purchase price of the original quota. * * @param account - the ram seller account, @@ -1059,9 +881,7 @@ namespace eosiosystem { void sellram( const name& account, int64_t bytes ); /** - * Refund action. - * - * @details This action is called after the delegation-period to claim all pending + * Refund action. This action is called after the delegation-period to claim all pending * unstaked tokens belonging to owner. * * @param owner - the owner of the tokens claimed. @@ -1071,6 +891,22 @@ namespace eosiosystem { // functions defined in voting.cpp + /** + * Register producer action. Register producer action, indicates that a particular account wishes to become a producer, + * this action will create a `producer_config` and a `producer_info` object for `producer` scope + * in producers tables. + * + * @param producer - account registering to be a producer candidate, + * @param producer_key - the public key of the block producer, this is the key used by block producer to sign blocks, + * @param url - the url of the block producer, normally the url of the block producer presentation website, + * @param location - is the country code as defined in the ISO 3166, https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes + * + * @pre Producer to register is an account + * @pre Authority of producer to register + */ + [[eosio::action]] + void regproducer( const name& producer, const public_key& producer_key, const std::string& url, uint16_t location ); + /** * Register producer action. * @@ -1079,19 +915,18 @@ namespace eosiosystem { * in producers tables. * * @param producer - account registering to be a producer candidate, - * @param producer_key - the public key of the block producer, this is the key used by block producer to sign blocks, + * @param producer_authority - the weighted threshold multisig block signing authority of the block producer used to sign blocks, * @param url - the url of the block producer, normally the url of the block producer presentation website, * @param location - is the country code as defined in the ISO 3166, https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes * - * @pre Producer is not already registered * @pre Producer to register is an account * @pre Authority of producer to register */ [[eosio::action]] - void regproducer( const name& producer, const public_key& producer_key, const std::string& url, uint16_t location ); + void regproducer2( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); /** - * Unregister producer action. + * Unregister producer action. Deactivate the block producer with account name `producer`. * * @details Deactivate the block producer with account name `producer`. * @param producer - the block producer account to unregister. @@ -1100,18 +935,14 @@ namespace eosiosystem { void unregprod( const name& producer ); /** - * Set ram action. - * - * @details Set the ram supply. + * Set ram action sets the ram supply * @param max_ram_size - the amount of ram supply to set. */ [[eosio::action]] void setram( uint64_t max_ram_size ); /** - * Set ram rate action. - - * @details Sets the rate of increase of RAM in bytes per block. It is capped by the uint16_t to + * Set ram rate action. Sets the rate of increase of RAM in bytes per block. It is capped by the uint16_t to * a maximum rate of 3 TB per year. If update_ram_supply hasn't been called for the most recent block, * then new ram will be allocated at the old rate up to the present block before switching the rate. * @@ -1121,9 +952,7 @@ namespace eosiosystem { void setramrate( uint16_t bytes_per_block ); /** - * Vote producer action. - * - * @details Votes for a set of producers. This action updates the list of `producers` voted for, + * Vote producer action. Votes for a set of producers. This action updates the list of `producers` voted for, * for `voter` account. If voting for a `proxy`, the producer votes will not change until the * proxy updates their own vote. Voter can vote for a proxy __or__ a list of at most 30 producers. * Storage change is billed to `voter`. @@ -1149,9 +978,7 @@ namespace eosiosystem { void voteproducer( const name& voter, const name& proxy, const std::vector& producers ); /** - * Register proxy action. - * - * @details Set `proxy` account as proxy. + * Register proxy action. Set `proxy` account as proxy. * An account marked as a proxy can vote with the weight of other accounts which * have selected it as a proxy. Other accounts must refresh their voteproducer to * update the proxy's weight. @@ -1167,29 +994,22 @@ namespace eosiosystem { void regproxy( const name& proxy, bool isproxy ); /** - * Set the blockchain parameters - * - * @details Set the blockchain parameters. By tunning these parameters a degree of + * Set the blockchain parameters Set the blockchain parameters. By tunning these parameters a degree of * customization can be achieved. * @param params - New blockchain parameters to set. */ [[eosio::action]] void setparams( const eosio::blockchain_parameters& params ); - // functions defined in producer_pay.cpp /** - * Claim rewards action. - * - * @details Claim block producing and vote rewards. + * Claim rewards action. Claim block producing and vote rewards. * @param owner - producer account claiming per-block and per-vote rewards. */ [[eosio::action]] void claimrewards( const name& owner ); /** - * Set privilege status for an account. - * - * @details Allows to set privilege status for an account (turn it on/off). + * Set privilege status for an account. 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. */ @@ -1197,18 +1017,14 @@ namespace eosiosystem { void setpriv( const name& account, uint8_t is_priv ); /** - * Remove producer action. - * - * @details Deactivates a producer by name, if not found asserts. + * Remove producer action. Deactivates a producer by name, if not found asserts. * @param producer - the producer account to deactivate. */ [[eosio::action]] void rmvproducer( const name& producer ); /** - * Update revision action. - * - * @details Updates the current revision. + * Update revision action. Updates the current revision. * @param revision - it has to be incremented by 1 compared with current revision. * * @pre Current revision can not be higher than 254, and has to be smaller @@ -1218,9 +1034,7 @@ namespace eosiosystem { void updtrevision( uint8_t revision ); /** - * Bid name action. - * - * @details Allows an account `bidder` to place a bid for a name `newname`. + * Bid name action. Allows an account `bidder` to place a bid for a name `newname`. * @param bidder - the account placing the bid, * @param newname - the name the bid is placed for, * @param bid - the amount of system tokens payed for the bid. @@ -1239,9 +1053,7 @@ namespace eosiosystem { void bidname( const name& bidder, const name& newname, const asset& bid ); /** - * Bid refund action. - * - * @details Allows the account `bidder` to get back the amount it bid so far on a `newname` name. + * Bid refund action. Allows the account `bidder` to get back the amount it bid so far on a `newname` name. * * @param bidder - the account that gets refunded, * @param newname - the name for which the bid was placed and now it gets refunded for. @@ -1250,23 +1062,9 @@ namespace eosiosystem { void bidrefund( const name& bidder, const name& newname ); /** - * Set inflation action. - * - * @details Change the annual inflation rate of the core token supply and specify how + * Change the annual inflation rate of the core token supply and specify how * the new issued tokens will be distributed based on the following structure. - * - * +----+ +----------------+ - * +rate| +--------->|per vote reward | - * +--+-+ | +----------------+ - * | +-----+------+ - * | +----->| bp rewards | - * v | +-----+------+ - * +-+--+---+-+ | +----------------+ - * |new tokens| +--------->|per block reward| - * +----+-----+ +----------------+ - * | +------------+ - * +----->| savings | - * +------------+ + * * @param annual_rate - Annual inflation rate of the core token supply. * (eg. For 5% Annual inflation => annual_rate=500 @@ -1316,6 +1114,7 @@ namespace eosiosystem { using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; + using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; using unregprod_action = eosio::action_wrapper<"unregprod"_n, &system_contract::unregprod>; using setram_action = eosio::action_wrapper<"setram"_n, &system_contract::setram>; using setramrate_action = eosio::action_wrapper<"setramrate"_n, &system_contract::setramrate>; @@ -1386,7 +1185,8 @@ namespace eosiosystem { const asset& stake_net_quantity, const asset& stake_cpu_quantity, bool transfer ); void update_voting_power( const name& voter, const asset& total_update ); - // defined in voting.hpp + // defined in voting.cpp + void register_producer( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); void update_elected_producers( const block_timestamp& timestamp ); void update_votes( const name& voter, const name& proxy, const std::vector& producers, bool voting ); void propagate_weight_change( const voter_info& voter ); @@ -1429,5 +1229,4 @@ namespace eosiosystem { registration<&system_contract::update_rex_stake> vote_stake_updater{ this }; }; - /** @}*/ // end of @defgroup eosiosystem eosio.system -} /// eosiosystem +} diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 999ea7d71..03782cb12 100644 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -60,4 +60,4 @@ namespace eosiosystem { typedef eosio::multi_index< "rammarket"_n, exchange_state > rammarket; /** @}*/ // enf of @addtogroup eosiosystem -} /// namespace eosiosystem +} /// namespace eosiosystem \ No newline at end of file diff --git a/contracts/eosio.system/include/eosio.system/rex.results.hpp b/contracts/eosio.system/include/eosio.system/rex.results.hpp index b5a1949c9..29af85339 100644 --- a/contracts/eosio.system/include/eosio.system/rex.results.hpp +++ b/contracts/eosio.system/include/eosio.system/rex.results.hpp @@ -8,20 +8,47 @@ using eosio::action_wrapper; using eosio::asset; using eosio::name; +/** + * The actions `buyresult`, `sellresult`, `rentresult`, and `orderresult` of `rex.results` are all no-ops. + * They are added as inline convenience actions to `rentnet`, `rentcpu`, `buyrex`, `unstaketorex`, and `sellrex`. + * An inline convenience action does not have any effect, however, + * its data includes the result of the parent action and appears in its trace. + */ class [[eosio::contract("rex.results")]] rex_results : eosio::contract { public: using eosio::contract::contract; + /** + * Buyresult action. + * + * @param rex_received - amount of tokens used in buy order + */ [[eosio::action]] void buyresult( const asset& rex_received ); + /** + * Sellresult action. + * + * @param proceeds - amount of tokens used in sell order + */ [[eosio::action]] void sellresult( const asset& proceeds ); + /** + * Orderresult action. + * + * @param owner - the owner of the order + * @param proceeds - amount of tokens used in order + */ [[eosio::action]] void orderresult( const name& owner, const asset& proceeds ); + /** + * Rentresult action. + * + * @param rented_tokens - amount of rented tokens + */ [[eosio::action]] void rentresult( const asset& rented_tokens ); diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index bb08ca409..08d146092 100644 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -14,23 +14,16 @@ namespace eosio { using std::string; /** - * @defgroup eosiotoken eosio.token - * @ingroup eosiocontracts - * - * eosio.token contract - * - * @details eosio.token contract defines the structures and actions that allow users to create, issue, and manage + * eosio.token contract defines the structures and actions that allow users to create, issue, and manage * tokens on eosio based blockchains. - * @{ */ class [[eosio::contract("eosio.token")]] token : public contract { public: using contract::contract; /** - * Create action. + * Allows `issuer` account to create a token in supply of `maximum_supply`. If validation is successful a new entry in statstable for token symbol scope gets created. * - * @details Allows `issuer` account to create a token in supply of `maximum_supply`. * @param issuer - the account that creates the token, * @param maximum_supply - the maximum supply set for the token created. * @@ -38,16 +31,12 @@ namespace eosio { * @pre Token symbol must not be already created, * @pre maximum_supply has to be smaller than the maximum supply allowed by the system: 1^62 - 1. * @pre Maximum supply must be positive; - * - * If validation is successful a new entry in statstable for token symbol scope gets created. */ [[eosio::action]] void create( const name& issuer, const asset& maximum_supply); /** - * Issue action. - * - * @details This action issues to `to` account a `quantity` of tokens. + * This action issues to `to` account a `quantity` of tokens. * * @param to - the account to issue tokens to, it must be the same as the issuer, * @param quntity - the amount of tokens to be issued, @@ -57,9 +46,7 @@ namespace eosio { void issue( const name& to, const asset& quantity, const string& memo ); /** - * Retire action. - * - * @details The opposite for create action, if all validations succeed, + * The opposite for create action, if all validations succeed, * it debits the statstable.supply amount. * * @param quantity - the quantity of tokens to retire, @@ -69,9 +56,7 @@ namespace eosio { void retire( const asset& quantity, const string& memo ); /** - * Transfer action. - * - * @details Allows `from` account to transfer to `to` account the `quantity` tokens. + * Allows `from` account to transfer to `to` account the `quantity` tokens. * One account is debited and the other is credited with quantity tokens. * * @param from - the account to transfer from, @@ -85,9 +70,7 @@ namespace eosio { const asset& quantity, const string& memo ); /** - * Open action. - * - * @details Allows `ram_payer` to create an account `owner` with zero balance for + * Allows `ram_payer` to create an account `owner` with zero balance for * token `symbol` at the expense of `ram_payer`. * * @param owner - the account to be created, @@ -101,9 +84,7 @@ namespace eosio { void open( const name& owner, const symbol& symbol, const name& ram_payer ); /** - * Close action. - * - * @details This action is the opposite for open, it closes the account `owner` + * This action is the opposite for open, it closes the account `owner` * for token `symbol`. * * @param owner - the owner account to execute the close action for, @@ -116,9 +97,7 @@ namespace eosio { void close( const name& owner, const symbol& symbol ); /** - * Get supply method. - * - * @details Gets the supply for token `sym_code`, created by `token_contract_account` account. + * Gets the supply for token `sym_code`, created by `token_contract_account` account. * * @param token_contract_account - the account to get the supply for, * @param sym_code - the symbol to get the supply for. @@ -131,9 +110,7 @@ namespace eosio { } /** - * Get balance method. - * - * @details Get the balance for a token `sym_code` created by `token_contract_account` account, + * Get the balance for a token `sym_code` created by `token_contract_account` account, * for account `owner`. * * @param token_contract_account - the token creator account, @@ -174,5 +151,5 @@ namespace eosio { void sub_balance( const name& owner, const asset& value ); void add_balance( const name& owner, const asset& value, const name& ram_payer ); }; - /** @}*/ // end of @defgroup eosiotoken eosio.token -} /// namespace eosio + +} diff --git a/docs.json b/docs.json new file mode 100644 index 000000000..2d4e43af7 --- /dev/null +++ b/docs.json @@ -0,0 +1,40 @@ +{ + "name": "eosio.contracts", + "generators": [ + { + "name": "collate_markdown", + "options": { + "docs_dir": "docs" + } + }, + { + "name": "mdjavadoc", + "options": { + "source_dirs": [ + "contracts/eosio.token/include/eosio.token/", + "contracts/eosio.wrap/include/eosio.wrap/", + "contracts/eosio.bios/include/eosio.bios/", + "contracts/eosio.system/include/eosio.system/", + "contracts/eosio.msig/include/eosio.msig/" + ], + "output_dir": "action-reference" + } + } + ], + "skip_default_filters": true, + "filters": [ + { + "name": "sanitize", + "options": { + "exclude": ["action-reference"] + } + }, + { + "name": "capitalize", + "options": { + "mode": "all", + "exclude": ["action-reference"] + } + } + ] +} diff --git a/docs/02_compile-and-deploy.md b/docs/02_compile-and-deploy.md new file mode 100644 index 000000000..06fbd8610 --- /dev/null +++ b/docs/02_compile-and-deploy.md @@ -0,0 +1,78 @@ +## How to compile the eosio.contracts + +### Preconditions +Ensure an appropriate version of `eosio.cdt` is installed. Installing `eosio.cdt` from binaries is sufficient, follow the [`eosio.cdt` installation instructions steps](https://github.com/EOSIO/eosio.cdt/tree/master/#binary-releases) to install it. To verify if you have `eosio.cdt` installed and its version run the following command + +```sh +eosio-cpp -v +``` + +#### Build contracts using the build script + +##### To build contracts alone +Run the `build.sh` script in the top directory to build all the contracts. + +##### To build the contracts and unit tests +1. Ensure an appropriate version of `eosio` has been built from source and installed. Installing `eosio` from binaries `is not` sufficient. You can find instructions on how to do it [here](https://github.com/EOSIO/eos/blob/master/README.md) in section `Building from Sources`. +2. Run the `build.sh` script in the top directory with the `-t` flag to build all the contracts and the unit tests for these contracts. + +#### Build contracts manually + +To compile the `eosio.contracts` execute the following commands. + +On all platforms except macOS: +```sh +cd you_local_path_to/eosio.contracts/ +rm -fr build +mkdir build +cd build +cmake .. +make -j$( nproc ) +cd .. +``` + +For macOS: +```sh +cd you_local_path_to/eosio.contracts/ +rm -fr build +mkdir build +cd build +cmake .. +make -j$(sysctl -n hw.ncpu) +cd .. +``` + +### After build: +* If the build was configured to also build unit tests, the unit tests executable is placed in the _build/tests_ folder and is named __unit_test__. +* The contracts (both `.wasm` and `.abi` files) are built into their corresponding _build/contracts/\_ folder. +* Finally, simply use __cleos__ to _set contract_ by pointing to the previously mentioned directory for the specific contract. + +## To deploy eosio.bios contract execute the following command: +Let's assume your account name to which you want to deploy the contract is `testerbios` +``` +cleos set contract testerbios you_local_path_to/eosio.contracts/build/contracts/eosio.bios/ -p testerbios +``` + +## To deploy eosio.msig contract execute the following command: +Let's assume your account name to which you want to deploy the contract is `testermsig` +``` +cleos set contract testermsig you_local_path_to/eosio.contracts/build/contracts/eosio.msig/ -p testermsig +``` + +## To deploy eosio.system contract execute the following command: +Let's assume your account name to which you want to deploy the contract is `testersystem` +``` +cleos set contract testersystem you_local_path_to/eosio.contracts/build/contracts/eosio.system/ -p testersystem +``` + +## To deploy eosio.token contract execute the following command: +Let's assume your account name to which you want to deploy the contract is `testertoken` +``` +cleos set contract testertoken you_local_path_to/eosio.contracts/build/contracts/eosio.token/ -p testertoken +``` + +## To deploy eosio.wrap contract execute the following command: +Let's assume your account name to which you want to deploy the contract is `testerwrap` +``` +cleos set contract testerwrap you_local_path_to/eosio.contracts/build/contracts/eosio.wrap/ -p testerwrap +``` \ No newline at end of file diff --git a/docs/03_guides/01_upgrading-the-eosio.system-contract.md b/docs/03_guides/01_upgrading-the-eosio.system-contract.md new file mode 100644 index 000000000..953ce0730 --- /dev/null +++ b/docs/03_guides/01_upgrading-the-eosio.system-contract.md @@ -0,0 +1,211 @@ +## Upgrading the system contract + +### Indirect method using eosio.msig contract + +Cleos currently provides tools to propose an action with the eosio.msig contract, but it does not provide an easy interface to propose a custom transaction. + +So, at the moment it is difficult to propose an atomic transaction with multiple actions (for example `eosio::setcode` followed by `eosio::setabi`). + +The advantage of the eosio.msig method is that it makes coordination much easier and does not place strict time limits (less than 9 hours) on signature collection. + +The disadvantage of the eosio.msig method is that it requires the proposer to have sufficient RAM to propose the transaction and currently cleos does not provide convenient tools to use it with custom transactions like the one that would be necessary to atomically upgrade the system contract. + +For now, it is recommended to use the direct method to upgrade the system contract. + +### Direct method (avoids using eosio.msig contract) + +Each of the top 21 block producers should do the following: + +1. Get current system contract for later comparison (actual hash and ABI on the main-net blockchain will be different): + +``` +$ cleos get code -c original_system_contract.wast -a original_system_contract.abi eosio +code hash: cc0ffc30150a07c487d8247a484ce1caf9c95779521d8c230040c2cb0e2a3a60 +saving wast to original_system_contract.wast +saving abi to original_system_contract.abi +``` + +2. Generate the unsigned transaction which upgrades the system contract: + +``` +$ cleos set contract -s -j -d eosio contracts/eosio.system | tail -n +4 > upgrade_system_contract_trx.json +``` + +The first few lines of the generated file should be something similar to (except with very different numbers for `expiration`, `ref_block_num`, and `ref_block_prefix`): + +``` +{ + "expiration": "2018-06-15T22:17:10", + "ref_block_num": 4552, + "ref_block_prefix": 511016679, + "max_net_usage_words": 0, + "max_cpu_usage_ms": 0, + "delay_sec": 0, + "context_free_actions": [], + "actions": [{ + "account": "eosio", + "name": "setcode", + "authorization": [{ + "actor": "eosio", + "permission": "active" + } + ], +``` + +and the last few lines should be: + +``` + } + ], + "transaction_extensions": [], + "signatures": [], + "context_free_data": [] +} +``` + +One of the top block producers should be chosen to lead the upgrade process. This lead producer should take their generated `upgrade_system_contract_trx.json`, rename it to `upgrade_system_contract_official_trx.json`, and do the following: + +3. Modify the `expiration` timestamp in `upgrade_system_contract_official_trx.json` to a time that is sufficiently far in the future to give enough time to collect all the necessary signatures, but not more than 9 hours from the time the transaction was generated. Also, keep in mind that the transaction will not be accepted into the blockchain if the expiration is more than 1 hour from the present time. + +4. Pass the `upgrade_system_contract_official_trx.json` file to all the other top 21 block producers. + +Then each of the top 21 block producers should do the following: + +5. Compare their generated `upgrade_system_contract_official_trx.json` file with the `upgrade_system_contract_official_trx.json` provided by the lead producer. The only difference should be in `expiration`, `ref_block_num`, `ref_block_prefix`, for example: + +TO DO: Shouldn't one of the files be upgrade_system_contract_trx.json? + +``` +$ diff upgrade_system_contract_official_trx.json upgrade_system_contract_trx.json +2,4c2,4 +< "expiration": "2018-06-15T22:17:10", +< "ref_block_num": 4552, +< "ref_block_prefix": 511016679, +--- +> "expiration": "2018-06-15T21:20:39", +> "ref_block_num": 4972, +> "ref_block_prefix": 195390844, +``` + +6. If the comparison is good, each block producer should proceed with signing the official upgrade transaction with the keys necessary to satisfy their active permission. If the block producer only has a single key (i.e the "active key") in the active permission of their block producing account, then they only need to generate one signature using that active key. This signing process can be done offline for extra security. + +First, the block producer should collect all the necessary information. Let us assume that the block producers active key pair is `(EOS5kBmh5kfo6c6pwB8j77vrznoAaygzoYvBsgLyMMmQ9B6j83i9c, 5JjpkhxAmEfynDgSn7gmEKEVcBqJTtu6HiQFf4AVgGv5A89LfG3)`. The block producer needs their active private key (`5JjpkhxAmEfynDgSn7gmEKEVcBqJTtu6HiQFf4AVgGv5A89LfG3` in this example), the `upgrade_system_contract_official_trx.json`, and the `chain_id` (`d0242fb30b71b82df9966d10ff6d09e4f5eb6be7ba85fd78f796937f1959315e` in this example) which can be retrieved through `cleos get info`. + +Then on a secure computer the producer can sign the transaction (the producer will need to paste in their private key when prompted): + +``` +$ cleos sign --chain-id d0242fb30b71b82df9966d10ff6d09e4f5eb6be7ba85fd78f796937f1959315e upgrade_system_contract_trx.json | tail -n 5 +private key: "signatures": [ + "SIG_K1_JzABB9gzDGwUHaRmox68UNcfxMVwMnEXqqS1MvtsyUX8KGTbsZ5aZQZjHD5vREQa5BkZ7ft8CceLBLAj8eZ5erZb9cHuy5" + ], + "context_free_data": [] +} +``` + +Make sure to use the `chain_id` of the actual main-net blockchain that the transaction will be submitted to and not the example `chain_id` provided above. + +The output should include the signature (in this case `"SIG_K1_JzABB9gzDGwUHaRmox68UNcfxMVwMnEXqqS1MvtsyUX8KGTbsZ5aZQZjHD5vREQa5BkZ7ft8CceLBLAj8eZ5erZb9cHuy5"`) which the producer should then send to the lead producer. + +When the lead producer collects 15 producer signatures, the lead producer should do the following: + +7. Make a copy of the `upgrade_system_contract_official_trx.json` and call it `upgrade_system_contract_official_trx_signed.json`, and then modify the `upgrade_system_contract_official_trx_signed.json` so that the `signatures` field includes all 15 collected signatures. So the tail end of `upgrade_system_contract_official_trx_signed.json` could look something like: + +``` +$ cat upgrade_system_contract_official_trx_signed.json | tail -n 20 + "transaction_extensions": [], + "signatures": [ + "SIG_K1_JzABB9gzDGwUHaRmox68UNcfxMVwMnEXqqS1MvtsyUX8KGTbsZ5aZQZjHD5vREQa5BkZ7ft8CceLBLAj8eZ5erZb9cHuy5", + "SIG_K1_Kj7XJxnPQSxEXZhMA8uK3Q1zAxp7AExzsRd7Xaa7ywcE4iUrhbVA3B6GWre5Ctgikb4q4CeU6Bvv5qmh9uJjqKEbbjd3sX", + "SIG_K1_KbE7qyz3A9LoQPYWzo4e6kg5ZVojQVAkDKuufUN2EwVUqtFhtjmGoC6QPQqLi8J7ftiysBp52wJBPjtNQUfZiGpGMsnZ1f", + "SIG_K1_KdQsE7ahHA9swE9SDGg4oF6XahpgHmZfEgQAy9KPBLd9HuwrF6c8m6jz43zizK2oo32Ejg1DYuMfoEvJgVfXo81jsqTHvA", + "SIG_K1_K6228Hi2z1WabgVdf5bk2UdKyyDSVFwkMaagTn9oLVDV8rCX7aQcjY94c39ah2CkLTsTEqzTPAYknJ8m2m9B7npPkHaFzc", + "SIG_K1_Jzdx75hBCA2WSaXgrupmrNbcQocUCsP8r1BKkPXMreiAKPZDwX9J3G8fS1HhyqWjc7FbukwZf8sVRdS3wKbJVpytqXe7Nn", + "SIG_K1_KW7Qu2SdPD3zuQKh2ziFLzn9QbKqeMpeiemULky5Bbg1Mst6ijbCX3k2AVFGNFLkNLA36PM1WAT5oipzu1B1K7ymRxTx1Z", + "SIG_K1_KXJf1KZNpz73YFKKE7u6jFgsQ8XcX3yA7rDX6ZmG1Qfnc9FLLmT1WViv4bwcPbxaEYfR6SNWfk5cCR9eao2si1soqkXq92", + "SIG_K1_JynjkHFT5UFGDpEcqdriXTzCGCwS36Xztq4UAWQHLQgRUZT2YFoLhUcc87kvUteqCUGVxsmSbfgWv1KLy24voKN4Qs5zTe", + "SIG_K1_JxhfCaGBhuNShpDHn7j1CryG3iSebvfi7FUnJsfkXNTiwLyq2NDBkeakwjCMWFbzr6qqWuMDLjfXbzdtU17f1wCXMjKSgk", + "SIG_K1_KcMSz89QG1ZRFNrXc69R63d5KXbJA8CBjNPYv1VEA3TRfjqVYuhyaHpGXQN4RSKDq4ygr3UTRYBQQVutkJnR6zZ4Ssgd7R", + "SIG_K1_JuxT6bhUAbDs6Q2ppuKyKauduvbaJLxvh4gBH4e4A9yRhvUBT7w3DcvMyhdaor27Kbu29jnqhTbvXcb57QqKWQDpboLv7e", + "SIG_K1_K8BuFYpCiC5FhpVK8ZAzc3VUg7vz6WwLoWBrGN6nnuqUjngGqvHp3UxDVzcwhqccHdv8kdPXvF6G1NszwF1dd3wjCrHBYw", + "SIG_K1_KfH5ZirPwDk1RQKvJv2AGPfsJyPXvXLegZ7LvcPmRtjtMiErs1STXLNT8kiBfhZr4xkWRA5NR1kMF3d49DFMJiB2iWMXJc", + "SIG_K1_KjJB8jtcqpVe3r5jouFiAa9wJeYqoLMh5xrUV6kBF6UWfbYjimMWBJWz2ZPomGDsk7JtdUESVrYj1AhYbdp3X48KLm5Cev" + ], + "context_free_data": [] +} +``` + +8. Push the signed transaction to the blockchain: + +``` +$ cleos push transaction --skip-sign upgrade_system_contract_official_trx_signed.json +{ + "transaction_id": "202888b32e7a0f9de1b8483befac8118188c786380f6e62ced445f93fb2b1041", + "processed": { + "id": "202888b32e7a0f9de1b8483befac8118188c786380f6e62ced445f93fb2b1041", + "receipt": { + "status": "executed", + "cpu_usage_us": 4909, + "net_usage_words": 15124 + }, + "elapsed": 4909, + "net_usage": 120992, + "scheduled": false, + "action_traces": [{ +... +``` + +If you get an error message like the following: + +``` +Error 3090003: provided keys, permissions, and delays do not satisfy declared authorizations +Ensure that you have the related private keys inside your wallet and your wallet is unlocked. +``` + +That means that at least one of the signatures provided were bad. This may be because a producer signed the wrong transaction, used the wrong private key, or used the wrong chain ID. + +If you get an error message like the following: + +``` +Error 3090002: irrelevant signature included +Please remove the unnecessary signature from your transaction! +``` + +That means unnecessary signatures were included. If there are 21 active producers, only signatures from exactly 15 of those 21 active producers are needed. + +If you get an error message like the following: + +``` +Error 3040006: Transaction Expiration Too Far +Please decrease the expiration time of your transaction! +``` + +That means that the expiration time is more than 1 hour in the future and you need to wait some time before being allowed to push the transaction. + +If you get an error message like the following: + +``` +Error 3040005: Expired Transaction +Please increase the expiration time of your transaction! +``` + +That means the expiration time of the signed transaction has passed and this entire process has to restart from step 1. + +9. Assuming the transaction successfully executes, everyone can then verify that the new contract is in place: + +``` +$ cleos get code -c new_system_contract.wast -a new_system_contract.abi eosio +code hash: 9fd195bc5a26d3cd82ae76b70bb71d8ce83dcfeb0e5e27e4e740998fdb7b98f8 +saving wast to new_system_contract.wast +saving abi to new_system_contract.abi +$ diff original_system_contract.abi new_system_contract.abi +584,592d583 +< },{ +< "name": "deferred_trx_id", +< "type": "uint32" +< },{ +< "name": "last_unstake_time", +< "type": "time_point_sec" +< },{ +< "name": "unstaking", +< "type": "asset" +``` diff --git a/docs/03_guides/02_how-to-buy-ram.md b/docs/03_guides/02_how-to-buy-ram.md new file mode 100644 index 000000000..878757e35 --- /dev/null +++ b/docs/03_guides/02_how-to-buy-ram.md @@ -0,0 +1,8 @@ +## How buy RAM + +You can buy RAM using `cleos` command line tool or using a wallet that implements the buy RAM functionality. + +TO DO: verify and correct the next url +To buy ram using `cleos` check [how to buy ram](https://eosio.github.io/eos/cleos/how-to-buy-ram) + +To buy ram using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file diff --git a/docs/03_guides/03_how-to-stake.md b/docs/03_guides/03_how-to-stake.md new file mode 100644 index 000000000..bf2a1f381 --- /dev/null +++ b/docs/03_guides/03_how-to-stake.md @@ -0,0 +1,8 @@ +## How to stake tokens for CPU and/or NET bandwidth + +You can stake tokens for CPU and/or NET bandwidth using `cleos` command line tool or using a wallet that implements this functionality. + +TO DO: verify and correct the next url +To stake tokens for CPU and/or NET bandwidth using `cleos` check [how to stake resource](https://eosio.github.io/eos/cleos/how-to-stake-resource) + +To stake tokens for CPU and/or NET bandwidth using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file diff --git a/docs/03_guides/04_how-to-vote.md b/docs/03_guides/04_how-to-vote.md new file mode 100644 index 000000000..d27cccac0 --- /dev/null +++ b/docs/03_guides/04_how-to-vote.md @@ -0,0 +1,8 @@ +## How to vote + +You can vote using `cleos` command line tool or using a wallet that implements the vote functionality. + +TO DO: verify and correct the next url +To vote using `cleos` check [how to vote](https://eosio.github.io/eos/cleos/how-to-vote) + +To vote using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file diff --git a/docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md new file mode 100644 index 000000000..3693d37e6 --- /dev/null +++ b/docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -0,0 +1,126 @@ +## How to create, issue and transfer a token + +## Step 1: Obtain Contract Source + +Navigate to your contracts directory. + +```text +cd CONTRACTS_DIR +``` + +Pull the source +```text +git clone https://github.com/EOSIO/eosio.contracts --branch master --single-branch +``` + +```text +cd eosio.contracts/contracts/eosio.token +``` + +## Step 2: Create Account for Contract +[[info]] +| You may have to unlock your wallet first! + +```shell +cleos create account eosio eosio.token EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV +``` + +## Step 3: Compile the Contract + +```shell +eosio-cpp -I include -o eosio.token.wasm src/eosio.token.cpp --abigen +``` + +## Step 4: Deploy the Token Contract + +```shell +cleos set contract eosio.token CONTRACTS_DIR/eosio.contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active +``` + +Result should look similar to the one below: +```shell +Reading WASM from ... +Publishing contract... +executed transaction: 69c68b1bd5d61a0cc146b11e89e11f02527f24e4b240731c4003ad1dc0c87c2c 9696 bytes 6290 us +# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001aa011c60037f7e7f0060047f... +# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30000605636c6f73650002056f776e6572046e61... +warning: transaction executed locally, but may not be confirmed by the network yet ] +``` + +## Step 5: Create the Token + +```shell +cleos push action eosio.token create '[ "eosio", "1000000000.0000 SYS"]' -p eosio.token@active +``` + +Result should look similar to the one below: +```shell +executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles +# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} +``` + +An alternate approach uses named arguments: + +```shell +cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"1000000000.0000 SYS"}' -p eosio.token@active +``` + +Result should look similar to the one below: +```shell +executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles +# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} +``` +This command created a new token `SYS` with a precision of 4 decimals and a maximum supply of 1000000000.0000 SYS. To create this token requires the permission of the `eosio.token` contract. For this reason, `-p eosio.token@active` was passed to authorize the request. + +## Step 6: Issue Tokens + +The issuer can issue new tokens to the issuer account in our case `eosio`. + +```text +cleos push action eosio.token issue '[ "eosio", "100.0000 SYS", "memo" ]' -p eosio@active +``` + +Result should look similar to the one below: +```shell +executed transaction: a26b29d66044ad95edf0fc04bad3073e99718bc26d27f3c006589adedb717936 128 bytes 337 us +# eosio.token <= eosio.token::issue {"to":"eosio","quantity":"100.0000 SYS","memo":"memo"} +warning: transaction executed locally, but may not be confirmed by the network yet ] +``` + +## Step 7: Transfer Tokens + +Now that account `eosio` has been issued tokens, transfer some of them to account `bob`. + +```shell +cleos push action eosio.token transfer '[ "eosio", "bob", "25.0000 SYS", "m" ]' -p eosio@active +``` + +Result should look similar to the one below: +```text +executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d69f39d 128 bytes 497 us +# eosio.token <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} +# eosio <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} +# bob <= eosio.token::transfer {"from":"eosio","to":"bob","quantity":"25.0000 SYS","memo":"m"} +warning: transaction executed locally, but may not be confirmed by the network yet ] +``` +Now check if "bob" got the tokens using [cleos get currency balance](https://developers.eos.io/eosio-cleos/reference#currency-balance) + +```shell +cleos get currency balance eosio.token bob SYS +``` + +Result: +```text +25.00 SYS +``` + +Check "eosio's" balance, notice that tokens were deducted from the account + +```shell +cleos get currency balance eosio.token eosio SYS +``` + +Result: +```text +75.00 SYS +``` diff --git a/docs/eosio.msig.md b/docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md similarity index 89% rename from docs/eosio.msig.md rename to docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 2006a468c..f68dff871 100644 --- a/docs/eosio.msig.md +++ b/docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -1,16 +1,14 @@ -eosio.msig examples -------------------- +## eosio.msig examples -Cleos usage example for issuing tokens. ---------------------------------------- +### Cleos usage example for issuing tokens. -Prerequisites: +#### Prerequisites: - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account. - account 'treasury' is the issuer of SYS token. - account 'tester' exists. - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. -One user creates a proposal: +#### One user creates a proposal: ```` $ cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 SYS", "memo": ""}' -p tester @@ -18,8 +16,7 @@ executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]... ```` - -Another user reviews the transaction: +#### Another user reviews the transaction: ```` $ cleos multisig review tester test { @@ -60,8 +57,7 @@ $ cleos multisig review tester test } ```` - -And then approves it: +#### And then approves it: ```` $ cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury @@ -69,8 +65,7 @@ executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd951 # eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}} ```` - -First user initiates execution: +#### First user initiates execution: ```` $ cleos multisig exec tester test -p tester @@ -79,16 +74,15 @@ executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e ```` -Cleos usage example for transferring tokens. -------------------------------------------- +### Cleos usage example for transferring tokens. -Prerequisites: +#### Prerequisites: - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account. - account 'treasury' has at least 1.1000 SYS token balance. - account 'tester' exists. - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. -One user creates a proposal: +#### One user creates a proposal: ```` $ cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token transfer '{"from": "treasury", "to": "tester", "quantity": "1.0000 SYS", "memo": ""}' -p tester @@ -96,8 +90,7 @@ executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]... ```` - -Another user reviews the transaction: +#### Another user reviews the transaction: ```` $ cleos multisig review tester test { @@ -139,8 +132,7 @@ $ cleos multisig review tester test } ```` - -And then approves it: +#### And then approves it: ```` $ cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury @@ -148,8 +140,7 @@ executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd951 # eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}} ```` - -First user check account balance before executing the proposed transaction +#### First user check account balance before executing the proposed transaction ```` $ cleos get account tester ... @@ -160,8 +151,7 @@ SYS balances: total: 4.0487 SYS ```` - -First user initiates execution of proposed transaction: +#### First user initiates execution of proposed transaction: ```` $ cleos multisig exec tester test -p tester @@ -169,8 +159,7 @@ executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e # eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"} ```` - -First user can check account balance, it should be increased by 1.0000 SYS +#### First user can check account balance, it should be increased by 1.0000 SYS ```` $ cleos get account tester ... diff --git a/docs/eosio.wrap.md b/docs/03_guides/07_how-to-use-eosio.wrap.md similarity index 100% rename from docs/eosio.wrap.md rename to docs/03_guides/07_how-to-use-eosio.wrap.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..9ef079987 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,211 @@ +## About System Contracts + +The EOSIO blockchain platform is unique in that the features and characteristics of the blockchain built on it are flexible, that is, they can be changed, or modified completely to suit each business case requirement. Core blockchain features such as consensus, fee schedules, account creation and modification, token economics, block producer registration, voting, multi-sig, etc., are implemented inside smart contracts which are deployed on the blockchain built on the EOSIO platform. + +Block.one implements and maintains EOSIO open source platform which contains, as an example, the system contracts encapsulating the base functionality for an EOSIO based blockchain. This document will detail each one of them, [eosio.bios](#eosiobios-system-contract), [eosio.system](#eosiosystem-system-contract), [eosio.msig](#eosiomsig-system-contract), [eosio.token](#eosiotoken-system-contract), [eosio.wrap](#eosiowrap-system-contract) along with a few other main concepts. + +## Concepts + +### System contracts, system accounts, priviledged accounts + +At the genesis of an EOSIO based blockchain, there is only one account present: eosio, which is the main system account. There are other system accounts, which are created by eosio, and control specific actions of the system contracts mentioned earlier. Note that we are introducing the notion of system contract/s and system account/s. Also note that privileged accounts are accounts which can execute a transaction while skipping the standard authorization check. To ensure that this is not a security hole, the permission authority over these accounts is granted to eosio.prods. + +As you just learned the relation between an account and a contract, we are adding here that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: + +|Account|Priviledged|Has contract|Description| +|---|---|---|---| +|eosio|Yes|It contains the `eosio.system` contract|The main system account on an EOSIO based blockchain.| +|eosio.msig|Yes|It contains the `eosio.msig` contract|Allows the signing of a multi-sig transaction proposal for later execution if all required parties sign the proposal before the expiration time.| +|eosio.wrap|Yes|It contains the `eosio.wrap` contract.|Simplifies block producer superuser actions by making them more readable and easier to audit.| +|eosio.token|No|It contains the `eosio.token` contract.|Defines the structures and actions allowing users to create, issue, and manage tokens on EOSIO based blockchains.| +|eosio.names|No|No|The account which is holding funds from namespace auctions.| +|eosio.bpay|No|No|The account that pays the block producers for producing blocks. It assigns 0.25% of the inflation based on the amount of blocks a block producer created in the last 24 hours.| +|eosio.prods|No|No|The account representing the union of all current active block producers permissions.| +|eosio.ram|No|No|The account that keeps track of the SYS balances based on users actions of buying or selling RAM.| +|eosio.ramfee|No|No|The account that keeps track of the fees collected from users RAM trading actions: 0.5% from the value of each trade goes into this account.| +|eosio.saving|No|No|The account which holds the 4% of network inflation.| +|eosio.stake|No|No|The account that keeps track of all SYS tokens which have been staked for NET or CPU bandwidth.| +|eosio.vpay|No|No|The account that pays the block producers accordingly with the votes won. It assigns 0.75% of inflation based on the amount of votes a block producer won in the last 24 hours.| +|eosio.rex|No|No|The account that keeps track of fees and balances resulted from REX related actions execution.| + +### RAM + +RAM is the memory (space, storage) where the blockchain stores data. If your contract needs to store data on the blockchain, like in a database, then it can store it in the blockchain's RAM using either a multi-index table, which can be found explained [here](https://developers.eos.io/eosio-cpp/v1.3.1/docs/db-api) and [here](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables) or a singleton, its definition can be found [here](https://github.com/EOSIO/eosio.cdt/blob/develop/libraries/eosiolib/singleton.hpp) and a sample of its usage [here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/contracts/eosio.system/eosio.system.hpp). +The EOSIO-based blockchains are known for their high performance, which is achieved also because the data stored on the blockchain is using RAM as the storage medium, and thus access to blockchain data is very fast, helping the performance benchmarks to reach levels no other blockchain has been able to. +RAM is a very important resource because of the following reasons: it is a limited resource, each EOSIO-based blockchain can have a different policy and rules around RAM, for example the public EOS blockchain started with 64GB of RAM and after that the block producers decided to increase the memory with 1KiB (1024 bytes) per day, thus increasing constantly the supply of RAM for the price of RAM to not grow too high because of the increased demand from blockchain applications; also RAM it is used in executing many actions that are available on the blockchain, creating a new account for example (it needs to store in the blockchain memory the new account's information), also when an account accepts a new type of token a new record has to be created somewhere in the blockchain memory that holds the balance of the new token accepted, and that memory, the storage space on the blockchain, has to be purchased either by the account that transfers the token or by the account that accepts the new token type. +RAM is a scarce resource priced according to the unique Bancor liquidity algorithm which is implemented in the system contract [here](https://github.com/EOSIO/eos/blob/905e7c85714aee4286fa180ce946f15ceb4ce73c/contracts/eosio.system/exchange_state.hpp). + +### CPU + +CPU is processing power, the amount of CPU an account has is measured in microseconds, it is referred to as "cpu bandwidth" on the cleos get account command output and represents the amount of processing time an account has at its disposal when pushing actions to a contract. + +### NET + +As CPU and RAM, NET is also a very important resource in EOSIO-based blockchains. NET is the network bandwidth measured in bytes of transactions and it is referred to as "net bandwidth" on the cleos get account command. This resource like CPU must be staked so that a contract's transactions can be executed. + +### Stake + +On EOSIO based blockchains, to be able to deploy and then interact with a smart contract via its implemented actions it needs to be backed up by resources allocated on the account where the smart contract is deployed to. The three resource types an EOSIO smart contract developer needs to know about are RAM, CPU and NET. You can __stake__ CPU and NET and you can __buy__ RAM. You will also find that staking/unstaking is at times referred to as delegating/undelegating. The economics of staking is also to provably commit to a promise that you'll hold the staked tokens, either for NET or CPU, for a pre-established period of time, in spite of inflation caused by minting new tokens in order to reward BPs for their services every 24 hours. + +### Vote + +In a EOSIO-based network the blockchain is kept alive by nodes which are interconnected into a mesh, communicating with each other via peer to peer protocols. Some of these nodes are elected, via a __voting__ process, by the token holders to be producer nodes. They produce blocks, validate them and reach consensus on what transactions are allowed in each block, their order, and what blocks are finalized and stored forever in the blockchain memory. This way the governance, the mechanism by which collective decisions are made, of the blockchain is achieved through the 21 active block producers which are appointed by token holders' __votes__. It's the 21 active block producers which continuously create the blockchain by creating blocks, and securing them by validating them, and reaching consensus. Consensus is reached when 2/3+1 active block producers agree on validity of a block, that is all transactions contained in it and their order. + +## System contracts defined in eosio.contracts + +1. [eosio.bios](#eosiobios-system-contract) +2. [eosio.system](#eosiosystem-system-contract) +3. [eosio.msig](#eosiomsig-system-contract) +4. [eosio.token](#eosiotoken-system-contract) +5. [eosio.wrap](#eosiowrap-system-contract) + +### eosio.bios system contract + +The `eosio.bios` is the first sample of system smart 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. + +The actions implemented and publicly exposed by `eosio.bios` system contract are: setpriv, setalimits, setglimits, setprods, setparams, reqauth, setabi. + +|Action name|Action description| +|---|---| +|setpriv|Set privilege status for an account.| +|setalimits|Set the resource limits of an account| +|setglimits|Not implemented yet.| +|setprods|Set a new list of active producers, that is, a new producers' schedule.| +|setparams|Set the blockchain parameters.| +|reqauth|Check if an account has authorization to access the current action.| +|setabi|Set the abi for a contract identified by an account name.| + +The above actions are enough to serve the functionality of a basic blockchain, however, a keen eye would notice that the actions listed above do not allow for creation of an account, nor updating permissions, and other important features. As we mentioned earlier, this sample system contract is minimalist in its implementation, therefore it relies also on some native EOSIO actions. These native actions are not implemented in the `eosio.bios` system contract, they are implemented at the EOSIO chain core level. In the `eosio.bios` contract they are simply declared and have no implementation, so they can show in the contracts ABI definition, and therefore users can push these actions to the account that holds the `eosio.bios` contract. When one of these actions are pushed to the chain, to the `eosio.bios` contract account holder, via a `cleos` command for example, the corresponding native action is executed by the blockchain first, [see the code here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L58), and then the `eosio.bios` contract `apply` method is invoked, [see the code here](https://github.com/EOSIO/eos/blob/3fddb727b8f3615917707281dfd3dd3cc5d3d66d/libraries/chain/apply_context.cpp#L69), but having no implementation and not being part of the `EOSIO_DISPATCH`, at the contract level, this action will be a NOP, it will do nothing when called from core EOSIO code. + +Below are listed the actions which are declared in the `eosio.bios` contract, mapped one-to-one with the native EOSIO actions, but having no implementation at the contract level: + +|Action name|Description| +|---|---| +|newaccount|Called after a new account is created. This code enforces resource-limit rules for new accounts as well as new account naming conventions.| +|updateauth|Updates the permission for an account.| +|deleteauth|Delete permission for an account.| +|linkauth|Assigns a specific action from a contract to a permission you have created.| +|unlinkauth|Assigns a specific action from a contract to a permission you have created.| +|canceldelay|Allows for cancellation of a deferred transaction.| +|onerror|Called every time an error occurs while a transaction was processed.| +|setcode|Allows for update of the contract code of an account.| + +### eosio.system system contract + +The `eosio.system` contract is another smart contract that Block.one provides an implementation for as a sample system contract. It is a version of `eosio.bios` only this time it is not minimalist, it contains more elaborated structures, classes, methods, and actions needed for an EOSIO based blockchain core functionality: +- Users can stake tokens for CPU and Network bandwidth, and then vote for producers or delegate their vote to a proxy. +- Producers can register in order to be voted for, and can claim per-block and per-vote rewards. +- Users can buy and sell RAM at a market-determined price. +- Users can bid on premium names. +- A resource exchange system, named REX, allows token holders to lend their tokens, and users to rent CPU and NET resources in return for a market-determined fee. + +The actions implemented and publicly exposed by the `eosio.system` system contract are presented in the table below. Just like the `eosio.bios` sample contract 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. + +|Action name|Action description| +|---|---| +|newaccount|Called after a new account is created. This code enforces resource-limits rules for new accounts as well as new account naming conventions.| +|updateauth|Updates the permission for an account.| +|deleteauth|Delete permission for an account.| +|linkauth|Assigns a specific action from a contract to a permission you have created.| +|unlinkauth|Assigns a specific action from a contract to a permission you have created.| +|canceldelay|Allows for cancellation of a deferred transaction.| +|onerror|Called every time an error occurs while a transaction was processed.| +|setabi|Allows for updates of the contract ABI of an account.| +|setcode|Allows for updates of the contract code of an account.| +|init|Initializes the system contract for a version and a symbol.| +|setram|Set the ram supply.| +|setramrate|Set the ram increase rate.| +|setparams|Set the blockchain parameters.| +|setpriv|Set privilege status for an account (turn it on/off).| +|setalimits|Set the resource limits of an account.| +|setacctram|Set the RAM limits of an account.| +|setacctnet|Set the NET limits of an account.| +|setacctcpu|Set the CPU limits of an account.| +|rmvproducer|Deactivates a producer by name, if not found asserts.| +|updtrevision|Updates the current revision.| +|bidname|Allows an account to place a bid for a name.| +|bidrefund|Allows an account to get back the amount it bid so far on a name.| +|deposit|Deposits core tokens to user REX fund.| +|withdraw|Withdraws core tokens from user REX fund.| +|buyrex|Buys REX in exchange for tokens taken out of user's REX fund by transferring core tokens from user REX fund and converting them to REX stake.| +|unstaketorex|Use staked core tokens to buy REX.| +|sellrex|Sells REX in exchange for core tokens by converting REX stake back into core tokens at current exchange rate.| +|cnclrexorder|Cancels unfilled REX sell order by owner if one exists.| +|rentcpu|Use payment to rent as many SYS tokens as possible as determined by market price and stake them for CPU for the benefit of receiver, after 30 days the rented core delegation of CPU will expire.| +|rentnet|Use payment to rent as many SYS tokens as possible as determined by market price and stake them for NET for the benefit of receiver, after 30 days the rented core delegation of NET will expire.| +|fundcpuloan|Transfers tokens from REX fund to the fund of a specific CPU loan in order to be used for loan renewal at expiry.| +|fundnetloan|Transfers tokens from REX fund to the fund of a specific NET loan in order to be used for loan renewal at expiry.| +|defcpuloan|Withdraws tokens from the fund of a specific CPU loan and adds them to the REX fund.| +|defnetloan|Withdraws tokens from the fund of a specific NET loan and adds them to the REX fund.| +|updaterex|Updates REX owner vote weight to current value of held REX tokens.| +|consolidate|Consolidates REX maturity buckets into one bucket that cannot be sold before 4 days.| +|mvtosavings|Moves a specified amount of REX to savings bucket.| +|mvfrsavings|Moves a specified amount of REX from savings bucket.| +|rexexec|Processes max CPU loans, max NET loans, and max queued sellrex orders. Action does not execute anything related to a specific user.| +|closerex|Deletes owner records from REX tables and frees used RAM. Owner must not have an outstanding REX balance.| +|buyrambytes|Increases receiver's ram in quantity of bytes provided.| +|buyram|Increases receiver's ram quota based upon current price and quantity of tokens provided.| +|sellram|Reduces quota my bytes and then performs an inline transfer of tokens to receiver based upon the average purchase price of the original quota.| +|delegatebw|Stakes SYS from the balance of one account for the benefit of another.| +|undelegatebw|Decreases the total tokens delegated by one account to another account and/or frees the memory associated with the delegation if there is nothing left to delegate.| +|refund|This action is called after the delegation-period to claim all pending unstaked tokens belonging to owner.| +|regproducer|Register producer action, indicates that a particular account wishes to become a producer.| +|unregprod|Deactivate the block producer with specified account.| +|voteproducer|Votes for a set of producers. This action updates the list of producers voted for, for given voter account.| +|regproxy|Set specified account as proxy.| +|onblock|This special action is triggered when a block is applied by the given producer and cannot be generated from any other source.| +|claimrewards|Claim block producing and vote rewards for block producer identified by an account.| + +### eosio.msig system contract + +The `eosio.msig` allows for the creation of proposed transactions which require authorization from a list of accounts, approval of the proposed transactions by those accounts required to approve it, and finally, it also allows the execution of the approved transactions on the blockchain. + +The workflow to propose, review, approve and then executed a transaction is describe in details [here](./03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md), and in short it can be described by the following: +- first you create a transaction json file, +- then you submit this proposal to the `eosio.msig` contract, and you also insert the account permissions required to approve this proposal into the command that submits the proposal to the blockchain, +- the proposal then gets stored on the blockchain by the `eosio.msig` contract, and is accessible for review and approval to those accounts required to approve it, +- after each of the appointed accounts required to approve the proposed transactions reviews and approves it, you can execute the proposed transaction. The `eosio.msig` contract will execute it automatically, but not before validating that the transaction has not expired, it is not cancelled, and it has been signed by all the permissions in the initial proposal's required permission list. + +These are the actions implemented and publicly exposed by the `eosio.msig` contract: +|Action name|Action description| +|---|---| +|propose|Creates a proposal containing one transaction.| +|approve|Approves an existing proposal.| +|unapprove|Revokes approval of an existing proposal.| +|cancel|Cancels an existing proposal.| +|exec|Allows an account to execute a proposal.| +|invalidate|Invalidate proposal.| + +### eosio.token system contract + +The `eosio.token` contract defines the structures and actions that allow users to create, issue, and manage tokens for EOSIO based blockchains. + +These are the public actions the `eosio.token` contract is implementing: +|Action name|Action description| +|---|---| +|create|Allows an account to create a token in a given supply amount.| +|issue|This action issues to an account a specific quantity of tokens.| +|open|Allows a first account to create another account with zero balance for specified token at the expense of first account.| +|close|This action is the opposite for `open` action, it closes the specified account for specified token.| +|transfer|Allows an account to transfer to another account the specified token quantity. One account is debited and the other is credited with the specified token quantity.| +|retire|This action is the opposite for `create` action. If all validations succeed, it debits the specified amount of tokens from the total balance.| + +The `eosio.token` sample contract demonstrates one way to implement a smart contract which allows for creation and management of tokens. This contract gives anyone the ability to create a token. It is possible for one to create a similar contract which suits different needs. However, it is recommended that if one only needs a token with the above listed actions, that one uses the `eosio.token` contract instead of developing their own. + +The `eosio.token` contract class also implements two useful public static methods: `get_supply` and `get_balance`. The first allows one to check the total supply of a specified token, created by an account and the second allows one to check the balance of a token for a specified account (the token creator account has to be specified as well). + +The `eosio.token` contract manages the set of tokens, accounts and their corresponding balances, by using two internal multi-index structures: the `accounts` and `stats`. The `accounts` multi-index table holds, for each row, instances of `account` object and the `account` object holds information about the balance of one token. If we remember how multi-index tables work, see [here](https://developers.eos.io/eosio-cpp/docs/using-multi-index-tables), then we understand also that the `accounts` table is scoped to an eosio account, and it keeps the rows indexed based on the token's symbol. This means that when one queries the `accounts` multi-index table for an account name the result is all the tokens that account holds at the moment. + +Similarly, the `stats` multi-index table, holds instances of `currency_stats` objects for each row, which contains information about current supply, maximum supply, and the creator account for a symbol token. The `stats` table is scoped to the token symbol. Therefore, when one queries the `stats` table for a token symbol the result is one single entry/row corresponding to the queried symbol token if it was previously created, or nothing, otherwise. + +### eosio.wrap system contract +The `eosio.wrap` system contract allows block producers to bypass authorization checks or run privileged actions with 15/21 producer approval and thus simplifies block producers superuser actions. It also makes these actions easier to audit. + +It does not give block producers any additional powers or privileges that do not already exist within the EOSIO based blockchains. As it is implemented, in an EOSIO based blockchain, 15/21 block producers can change an account's permissions or modify an account's contract code if they decided it is beneficial for the blockchain and community. + +However, the current method is opaque and leaves undesirable side effects on specific system accounts, and thus the `eosio.wrap `contract solves this matter by providing an easier method of executing important governance actions. + +The only action implemented by the `eosio.wrap` system contract is the `exec` action. This action allows for execution of a transaction, which is passed to the `exec` method in the form of a packed transaction in json format via the 'trx' parameter and the `executer` account that executes the transaction. The same `executer` account will also be used to pay the RAM and CPU fees needed to execute the transaction. + +Why is it easier for governance actions to be executed via this contract? +The answer to this question is explained in detailed [here](./03_guides/07_how-to-use-eosio.wrap.md) \ No newline at end of file From 45731a4fca22377c737876080c0eee9a56a259a2 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 28 Oct 2019 18:07:27 +0200 Subject: [PATCH 064/106] correct the wrong dependencies --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 04e491a69..a2497e35f 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ The following unprivileged contract(s) are also part of the system. * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio.cdt v1.7.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.7.0-rc1) -* [eosio v2.0.x](https://github.com/EOSIO/eos/releases/tag/v2.0.0-rc1) (optional dependency only needed to build unit tests) +* [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.2) +* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.1) (optional dependency only needed to build unit tests) To build the contracts follow the instructions in [`Compile and deploy` section](./docs/02_compile-and-deploy.md). From f7d0f704e1cbd748432c6ff901f8463d16c1de7e Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 28 Oct 2019 18:20:45 +0200 Subject: [PATCH 065/106] correction for parts which not supposed to be in 1.8.x but in 1.9.x only --- .../include/eosio.system/eosio.system.hpp | 44 +++++-------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index fa567ec0e..462aceddc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1,9 +1,7 @@ #pragma once #include -#include #include -#include #include #include #include @@ -180,24 +178,22 @@ namespace eosiosystem { // Defines `producer_info` structure to be stored in `producer_info` table, added after version 1.0 struct [[eosio::table, eosio::contract("eosio.system")]] producer_info { - name owner; - double total_votes = 0; - eosio::public_key producer_key; /// a packed public key object - bool is_active = true; - std::string url; - uint32_t unpaid_blocks = 0; - time_point last_claim_time; - uint16_t location = 0; - eosio::binary_extension producer_authority; // added in version 1.9.0 - + name owner; + double total_votes = 0; + eosio::public_key producer_key; /// a packed public key object + bool is_active = true; + std::string url; + uint32_t unpaid_blocks = 0; + time_point last_claim_time; + uint16_t location = 0; uint64_t primary_key()const { return owner.value; } double by_votes()const { return is_active ? -total_votes : total_votes; } bool active()const { return is_active; } - void deactivate() { producer_key = public_key(); producer_authority.reset(); is_active = false; } + void deactivate() { producer_key = public_key(); is_active = false; } // explicit serialization macro is not necessary, used here only to improve compilation time EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) - (unpaid_blocks)(last_claim_time)(location)(producer_authority) ) + (unpaid_blocks)(last_claim_time)(location) ) }; // Defines new producer info structure to be stored in new producer info table, added after version 1.3.0 @@ -907,24 +903,6 @@ namespace eosiosystem { [[eosio::action]] void regproducer( const name& producer, const public_key& producer_key, const std::string& url, uint16_t location ); - /** - * Register producer action. - * - * @details Register producer action, indicates that a particular account wishes to become a producer, - * this action will create a `producer_config` and a `producer_info` object for `producer` scope - * in producers tables. - * - * @param producer - account registering to be a producer candidate, - * @param producer_authority - the weighted threshold multisig block signing authority of the block producer used to sign blocks, - * @param url - the url of the block producer, normally the url of the block producer presentation website, - * @param location - is the country code as defined in the ISO 3166, https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes - * - * @pre Producer to register is an account - * @pre Authority of producer to register - */ - [[eosio::action]] - void regproducer2( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); - /** * Unregister producer action. Deactivate the block producer with account name `producer`. * @@ -1114,7 +1092,6 @@ namespace eosiosystem { using sellram_action = eosio::action_wrapper<"sellram"_n, &system_contract::sellram>; using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>; using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>; - using regproducer2_action = eosio::action_wrapper<"regproducer2"_n, &system_contract::regproducer2>; using unregprod_action = eosio::action_wrapper<"unregprod"_n, &system_contract::unregprod>; using setram_action = eosio::action_wrapper<"setram"_n, &system_contract::setram>; using setramrate_action = eosio::action_wrapper<"setramrate"_n, &system_contract::setramrate>; @@ -1186,7 +1163,6 @@ namespace eosiosystem { void update_voting_power( const name& voter, const asset& total_update ); // defined in voting.cpp - void register_producer( const name& producer, const eosio::block_signing_authority& producer_authority, const std::string& url, uint16_t location ); void update_elected_producers( const block_timestamp& timestamp ); void update_votes( const name& voter, const name& proxy, const std::vector& producers, bool voting ); void propagate_weight_change( const voter_info& voter ); From bf597f03371698423c3d498467075c0fc20a25f0 Mon Sep 17 00:00:00 2001 From: ovi Date: Mon, 28 Oct 2019 18:26:59 +0200 Subject: [PATCH 066/106] add missing precondition and wrong referenced source file in comments --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 462aceddc..9e06ff822 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -897,6 +897,7 @@ namespace eosiosystem { * @param url - the url of the block producer, normally the url of the block producer presentation website, * @param location - is the country code as defined in the ISO 3166, https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes * + * @pre Producer is not already registered * @pre Producer to register is an account * @pre Authority of producer to register */ @@ -1162,7 +1163,7 @@ namespace eosiosystem { const asset& stake_net_quantity, const asset& stake_cpu_quantity, bool transfer ); void update_voting_power( const name& voter, const asset& total_update ); - // defined in voting.cpp + // defined in voting.hpp void update_elected_producers( const block_timestamp& timestamp ); void update_votes( const name& voter, const name& proxy, const std::vector& producers, bool voting ); void propagate_weight_change( const voter_info& voter ); From f81c087e8b15f635604bb5201c894820e5c31468 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 31 Oct 2019 16:50:02 +0200 Subject: [PATCH 067/106] Take care of the last 4 TO DOs --- .../01_upgrading-the-eosio.system-contract.md | 2 -- docs/03_guides/02_how-to-buy-ram.md | 25 ++++++++++++--- docs/03_guides/03_how-to-stake.md | 30 ++++++++++++++--- docs/03_guides/04_how-to-vote.md | 32 ++++++++++++++++--- 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/docs/03_guides/01_upgrading-the-eosio.system-contract.md b/docs/03_guides/01_upgrading-the-eosio.system-contract.md index 953ce0730..2bd712fb4 100644 --- a/docs/03_guides/01_upgrading-the-eosio.system-contract.md +++ b/docs/03_guides/01_upgrading-the-eosio.system-contract.md @@ -73,8 +73,6 @@ Then each of the top 21 block producers should do the following: 5. Compare their generated `upgrade_system_contract_official_trx.json` file with the `upgrade_system_contract_official_trx.json` provided by the lead producer. The only difference should be in `expiration`, `ref_block_num`, `ref_block_prefix`, for example: -TO DO: Shouldn't one of the files be upgrade_system_contract_trx.json? - ``` $ diff upgrade_system_contract_official_trx.json upgrade_system_contract_trx.json 2,4c2,4 diff --git a/docs/03_guides/02_how-to-buy-ram.md b/docs/03_guides/02_how-to-buy-ram.md index 878757e35..2885c5143 100644 --- a/docs/03_guides/02_how-to-buy-ram.md +++ b/docs/03_guides/02_how-to-buy-ram.md @@ -1,8 +1,23 @@ -## How buy RAM +## Goal -You can buy RAM using `cleos` command line tool or using a wallet that implements the buy RAM functionality. +Setup an account that require multiple signatures for signing a transaction -TO DO: verify and correct the next url -To buy ram using `cleos` check [how to buy ram](https://eosio.github.io/eos/cleos/how-to-buy-ram) +## Before you begin -To buy ram using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file +* You have an account + +* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources + +* You have sufficient token allocated to your account + +* Install the currently supported version of cleos + +* Unlock your wallet + +## Steps + +Buys RAM in value of 0.1 SYS tokens for account `alice`: + +```shell +cleos system buyram alice alice "0.1 SYS" -p alice@active +``` \ No newline at end of file diff --git a/docs/03_guides/03_how-to-stake.md b/docs/03_guides/03_how-to-stake.md index bf2a1f381..83f3a8da7 100644 --- a/docs/03_guides/03_how-to-stake.md +++ b/docs/03_guides/03_how-to-stake.md @@ -1,8 +1,28 @@ -## How to stake tokens for CPU and/or NET bandwidth +## Goal -You can stake tokens for CPU and/or NET bandwidth using `cleos` command line tool or using a wallet that implements this functionality. +Stake resource for your account -TO DO: verify and correct the next url -To stake tokens for CPU and/or NET bandwidth using `cleos` check [how to stake resource](https://eosio.github.io/eos/cleos/how-to-stake-resource) +## Before you begin -To stake tokens for CPU and/or NET bandwidth using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file +* Install the currently supported version of cleos + +* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources + +* Understand the following: + * What is an account + * What is network bandwidth + * What is CPU bandwidth + +## Steps + +Stake 0.01 SYS network bandwidth for `alice` + +```shell +cleos system delegatebw alice alice "0 SYS" "0.01 SYS" +``` + +Stake 0.01 SYS CPU bandwidth for `alice`: + +```shell +cleos system delegatebw alice alice "0.01 SYS" "0 SYS" +``` \ No newline at end of file diff --git a/docs/03_guides/04_how-to-vote.md b/docs/03_guides/04_how-to-vote.md index d27cccac0..62654ba7c 100644 --- a/docs/03_guides/04_how-to-vote.md +++ b/docs/03_guides/04_how-to-vote.md @@ -1,8 +1,30 @@ -## How to vote +## Goal -You can vote using `cleos` command line tool or using a wallet that implements the vote functionality. +Vote for a block producer -TO DO: verify and correct the next url -To vote using `cleos` check [how to vote](https://eosio.github.io/eos/cleos/how-to-vote) +## Before you begin -To vote using a wallet check the wallet user's manual for each wallet has its own implementation. \ No newline at end of file +* Install the current supported version of cleos + +* Ensure the reference system contracts from `eosio.contracts` repository is deployed and used to manage system resources + +* Understand the following: + * What is a block producer + * How does voting works + +* Unlock your wallet + +## Steps + +Assume you are going to vote for blockproducer1 and blockproducer2 from an account called `eosiotestts2`, execute the following: + +```bash +cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 +``` + +You should see something like below: + +```bash +executed transaction: 2d8b58f7387aef52a1746d7a22d304bbbe0304481d7751fc4a50b619df62676d 128 bytes 374 us +# eosio <= eosio::voteproducer {"voter":"eosiotestts2","proxy":"","producers":["blockproducer1","blockproducer2"]} +``` \ No newline at end of file From 66f6ea2d6f316d72aea5348101ece507650f6b4f Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 31 Oct 2019 17:21:08 +0200 Subject: [PATCH 068/106] Remove documentation from private functions, private structs. --- .../include/eosio.bios/eosio.bios.hpp | 68 +------------------ .../include/eosio.system/exchange_state.hpp | 13 +--- .../include/eosio.token/eosio.token.hpp | 14 ---- 3 files changed, 3 insertions(+), 92 deletions(-) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 3fa4a4cdb..4f190b27d 100644 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -63,14 +63,6 @@ namespace eosio { 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; @@ -79,11 +71,6 @@ namespace eosio { 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; @@ -92,11 +79,6 @@ namespace eosio { 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; @@ -105,15 +87,6 @@ namespace eosio { 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; @@ -124,19 +97,6 @@ namespace eosio { 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; @@ -152,26 +112,9 @@ namespace eosio { (schedule_version)(new_producers)) }; - /** - * @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. - * - * @{ - */ class [[eosio::contract("eosio.bios")]] bios : public 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 * @@ -385,11 +328,6 @@ namespace eosio { [[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; @@ -398,9 +336,6 @@ namespace eosio { 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>; @@ -419,5 +354,4 @@ namespace eosio { 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 eosio +} diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 03782cb12..e07153566 100644 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -38,16 +38,7 @@ namespace eosiosystem { asset convert_from_exchange( connector& reserve, const asset& tokens ); asset convert( const asset& from, const symbol& to ); asset direct_convert( const asset& from, const symbol& to ); - /** - * Given two connector balances (inp_reserve and out_reserve), and an incoming amount - * of inp, this function calculates the delta out using Banacor equation. - * - * @param inp - input amount, same units as inp_reserve - * @param inp_reserve - the input connector balance - * @param out_reserve - the output connector balance - * - * @return int64_t - conversion output amount - */ + static int64_t get_bancor_output( int64_t inp_reserve, int64_t out_reserve, int64_t inp ); @@ -60,4 +51,4 @@ namespace eosiosystem { typedef eosio::multi_index< "rammarket"_n, exchange_state > rammarket; /** @}*/ // enf of @addtogroup eosiosystem -} /// namespace eosiosystem \ No newline at end of file +} /// namespace eosiosystem diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index 08d146092..d5e20164a 100644 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -96,12 +96,6 @@ namespace eosio { [[eosio::action]] void close( const name& owner, const symbol& symbol ); - /** - * Gets the supply for token `sym_code`, created by `token_contract_account` account. - * - * @param token_contract_account - the account to get the supply for, - * @param sym_code - the symbol to get the supply for. - */ static asset get_supply( const name& token_contract_account, const symbol_code& sym_code ) { stats statstable( token_contract_account, sym_code.raw() ); @@ -109,14 +103,6 @@ namespace eosio { return st.supply; } - /** - * Get the balance for a token `sym_code` created by `token_contract_account` account, - * for account `owner`. - * - * @param token_contract_account - the token creator account, - * @param owner - the account for which the token balance is returned, - * @param sym_code - the token for which the balance is returned. - */ static asset get_balance( const name& token_contract_account, const name& owner, const symbol_code& sym_code ) { accounts accountstable( token_contract_account, owner.value ); From f50526cce41ff42191dae496b84a36e221c07f65 Mon Sep 17 00:00:00 2001 From: ovi Date: Thu, 31 Oct 2019 17:42:50 +0200 Subject: [PATCH 069/106] final touches: use build everywhere instead of a mix of build and compile, fix some headings --- README.md | 2 +- ...le-and-deploy.md => 02_build-and-deploy.md} | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) rename docs/{02_compile-and-deploy.md => 02_build-and-deploy.md} (85%) diff --git a/README.md b/README.md index a2497e35f..5aa582d89 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Dependencies: * [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.2) * [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.1) (optional dependency only needed to build unit tests) -To build the contracts follow the instructions in [`Compile and deploy` section](./docs/02_compile-and-deploy.md). +To build the contracts follow the instructions in [`Build and deploy` section](./docs/02_build-and-deploy.md). ## Contributing diff --git a/docs/02_compile-and-deploy.md b/docs/02_build-and-deploy.md similarity index 85% rename from docs/02_compile-and-deploy.md rename to docs/02_build-and-deploy.md index 06fbd8610..b61b15133 100644 --- a/docs/02_compile-and-deploy.md +++ b/docs/02_build-and-deploy.md @@ -1,4 +1,4 @@ -## How to compile the eosio.contracts +## How to build the eosio.contracts ### Preconditions Ensure an appropriate version of `eosio.cdt` is installed. Installing `eosio.cdt` from binaries is sufficient, follow the [`eosio.cdt` installation instructions steps](https://github.com/EOSIO/eosio.cdt/tree/master/#binary-releases) to install it. To verify if you have `eosio.cdt` installed and its version run the following command @@ -18,7 +18,7 @@ Run the `build.sh` script in the top directory to build all the contracts. #### Build contracts manually -To compile the `eosio.contracts` execute the following commands. +To build the `eosio.contracts` execute the following commands. On all platforms except macOS: ```sh @@ -42,36 +42,38 @@ make -j$(sysctl -n hw.ncpu) cd .. ``` -### After build: +#### After build: * If the build was configured to also build unit tests, the unit tests executable is placed in the _build/tests_ folder and is named __unit_test__. * The contracts (both `.wasm` and `.abi` files) are built into their corresponding _build/contracts/\_ folder. * Finally, simply use __cleos__ to _set contract_ by pointing to the previously mentioned directory for the specific contract. -## To deploy eosio.bios contract execute the following command: +## How to deploy the eosio.contracts + +### To deploy eosio.bios contract execute the following command: Let's assume your account name to which you want to deploy the contract is `testerbios` ``` cleos set contract testerbios you_local_path_to/eosio.contracts/build/contracts/eosio.bios/ -p testerbios ``` -## To deploy eosio.msig contract execute the following command: +### To deploy eosio.msig contract execute the following command: Let's assume your account name to which you want to deploy the contract is `testermsig` ``` cleos set contract testermsig you_local_path_to/eosio.contracts/build/contracts/eosio.msig/ -p testermsig ``` -## To deploy eosio.system contract execute the following command: +### To deploy eosio.system contract execute the following command: Let's assume your account name to which you want to deploy the contract is `testersystem` ``` cleos set contract testersystem you_local_path_to/eosio.contracts/build/contracts/eosio.system/ -p testersystem ``` -## To deploy eosio.token contract execute the following command: +### To deploy eosio.token contract execute the following command: Let's assume your account name to which you want to deploy the contract is `testertoken` ``` cleos set contract testertoken you_local_path_to/eosio.contracts/build/contracts/eosio.token/ -p testertoken ``` -## To deploy eosio.wrap contract execute the following command: +### To deploy eosio.wrap contract execute the following command: Let's assume your account name to which you want to deploy the contract is `testerwrap` ``` cleos set contract testerwrap you_local_path_to/eosio.contracts/build/contracts/eosio.wrap/ -p testerwrap From 3f382c0cced83958d93ab7128af130ff7c8b912d Mon Sep 17 00:00:00 2001 From: dskvr Date: Fri, 1 Nov 2019 09:10:17 -0400 Subject: [PATCH 070/106] Do not provide documentation for get_core_symbol during this release. --- .../eosio.system/include/eosio.system/eosio.system.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 9e06ff822..a952edd98 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -83,7 +83,6 @@ namespace eosiosystem { * - Users can bid on premium names. * - A resource exchange system (REX) allows token holders to lend their tokens, * and users to rent CPU and Network resources in return for a market-determined fee. - * @{ */ // A name bid, which consists of: @@ -467,11 +466,8 @@ namespace eosiosystem { system_contract( name s, name code, datastream ds ); ~system_contract(); - /** - * Returns the core symbol by system account name - * - * @param system_account - the system account to get the core symbol for. - */ + // Returns the core symbol by system account name + // @param system_account - the system account to get the core symbol for. static symbol get_core_symbol( name system_account = "eosio"_n ) { rammarket rm(system_account, system_account.value); const static auto sym = get_core_symbol( rm ); From d0f979a559774b2c1f49eed00573d2d5c69cde64 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 4 Nov 2019 10:14:25 -0500 Subject: [PATCH 071/106] bump version to v1.8.0 --- CMakeLists.txt | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99738d46b..129994bb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 8) set(VERSION_PATCH 0) -set(VERSION_SUFFIX rc1) +#set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/README.md b/README.md index 5aa582d89..38a4d5cea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.8.0-rc1 +## Version : 1.8.0 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 bios, system, msig, wrap (formerly known as sudo) and token contracts. @@ -15,8 +15,8 @@ The following unprivileged contract(s) are also part of the system. * [eosio.token](./contracts/eosio.token) Dependencies: -* [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.2) -* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.1) (optional dependency only needed to build unit tests) +* [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.3) +* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.5) (optional dependency only needed to build unit tests) To build the contracts follow the instructions in [`Build and deploy` section](./docs/02_build-and-deploy.md). From 1b81cfda9c74dccb1ebcd05ade530c1eea9e7581 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 6 Nov 2019 12:53:20 -0500 Subject: [PATCH 072/106] Fix for determining eosio and cdt versions required for forked PRs. --- .cicd/build.sh | 3 ++- .cicd/helpers/dependency-info.sh | 17 ++++++++++------- .travis.yml | 5 +---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index bf97c186b..eb2228595 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -15,7 +15,7 @@ else export DOCKER_IMAGE fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} -CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" +CDT_COMMANDS="apt-get install -y wget && wget -q $CDT_URL -O eosio.cdt.deb && dpkg -i eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/\\\$(ls /usr/opt/eosio.cdt/)/bin:\\\$PATH" PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake -DBUILD_TESTS=true .. && make -j $JOBS" COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" @@ -31,4 +31,5 @@ while [[ "$(docker pull $DOCKER_IMAGE 2>&1 | grep -ice "manifest for $DOCKER_IMA sleep 60 done # run +echo "docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\"" eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" \ No newline at end of file diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index d24f74b32..940241d56 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -14,15 +14,18 @@ else exit 1 fi # search GitHub for commit hash by tag and branch, preferring tag if both match -if [[ $TRAVIS ]]; then - CDT_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') - EOSIO_COMMIT=$((curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -H "Authorization: token $key" -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') -else +if [[ "$BUILDKITE" == 'true' ]]; then CDT_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/tags/$CDT_VERSION && curl -s https://api.github.com/repos/EOSIO/eosio.cdt/git/refs/heads/$CDT_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') EOSIO_COMMIT=$((curl -s https://api.github.com/repos/EOSIO/eos/git/refs/tags/$EOSIO_VERSION && curl -s https://api.github.com/repos/EOSIO/eos/git/refs/heads/$EOSIO_VERSION) | jq '.object.sha' | sed "s/null//g" | sed "/^$/d" | tr -d '"' | sed -n '1p') + test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already + test -z "$EOSIO_COMMIT" && EOSIO_COMMIT=$(echo $EOSIO_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already +else + git clone https://github.com/EOSIO/eosio.cdt && cd eosio.cdt + git pull && git checkout $CDT_VERSION + CDT_COMMIT=$(git rev-parse --verify HEAD) + EOSIO_COMMIT=$(echo $EOSIO_VERSION | sed 's/\//\_/') + cd .. fi -test -z "$CDT_COMMIT" && CDT_COMMIT=$(echo $CDT_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already -echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_VERSION\"..." -test -z "$EOSIO_COMMIT" && EOSIO_COMMIT=$(echo $EOSIO_VERSION | tr -d '"' | tr -d "''" | cut -d ' ' -f 1) # if both searches returned nothing, the version is probably specified by commit hash already echo "Using eosio ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\"..." +echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_VERSION\"..." export CDT_URL="https://eos-public-oss-binaries.s3-us-west-2.amazonaws.com/${CDT_COMMIT:0:7}-eosio.cdt-ubuntu-18.04_amd64.deb" \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 516355254..c1d0e8ee1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,4 @@ matrix: script: ". ./.cicd/build.sh && ./.cicd/test.sh" notifications: webhooks: - secure: CEIaN/RNCYALwL+QgBhVlyq5DvomyMcmB+gUfdDabxJk55misbIAXkj7l3+1dvq4EeB8Vw3vSKAimfjpj0hGCopOPxPsE5SPYWx3czI7cBPvuu3S4NSmx6WEe+pjI3IexUVQXRLazhvvwB6D/vZnFlr3ECYj59K0fGoYOKW14oG2RLVP7Clx3qoo1O8y7F+Ia6fEp/Q4pvwgFKnUL4hJrCUefJwSKDH8Nxf4FF5U41RLE8Xhdqxo1zbZBpT30gaPERzBnTCO3ko5NIEI/WPruQgcRr/PVDTG1xYZ2XqImDb/fHZKqkOJSoOTH+2U2KBxfXCwLPzkz6CkpJ7v14VL4qoV/F5DA9/fTSB4+B6IWusFF8NhstMmeCw0vkfaO/8WW8VEYHXnlTPFAQZJEiEyIYDcyVnUXur0yFEkvr4ZdGDmUEv/AdClVJ7Ig7T4MF2K66Yqtj930VQhI5PSWMKIWFG+2eboBrmXet+Z+2GRhwCGm5knB4/bcDcg9E80cwUWVol6AxVO07n70Qx57qX9Tvz/Ay9ugtEY+xSDQQ+HkFw62MiPDsNhSFoUD+TNY+SnEe1qnciKhb2/1bNTkKMPjifjJmDWkfC07qrXsDBcj4cIgfj6vh8lBj7U6kg7vCjXeJeljgu0wcTDd+EprDHpfRwkoXi9UsnSw2HXAveZMP4= -env: - global: - secure: jE/hVrQwgGs4KDdBqtiaGb9QE7xg8tn9NK2xMyedsi1CzqSZwl1iLjoefD4nH2wYRCGWfTBFES7QtJbj7SZK0+eobwQMO+jyXSOBd8D8HqcT37UMOPYW72YY2UuZpSCinuLHkZxZnb5dGfMqXDIZ3Y3GIgxOAd2+a0Y6xLt0dfZvh4OH8KVc/wWtuAjh0kMYEoQV9gEyok7xnXNjSLbAbkVslQBKHv451oi8saIGQbFC3b1KSGlE9LBv0QAR9MLXlkYMF3tAfegTGzx/NUIwdOOJ6XoPWoUGWV/u/nWexjHwsb1MwqQHN+LWHRM39ehL46na4m32S/ro3wHmBXnxlF3ys8QH0PEpfJL+r8aKGOv3pmWE//x+Ias6K6RWzTMLRFqlDPGTAGgMRGFiyGhT1aRHXD+mC2RppXptBST9brhE7+lyVqzKYFFHi0SHxfRsSQLgGhIJTMBr2Jj5ORlT86BWdxj3P8VOitKif/RP1zuJBKr78EyLGDPvsJhmot/gPg3VAo2R+cyFqVBWig2PC2ylneSS2DptMV6qLlujA+Fr38diYacsMqhej3ukqVZGaOecSIJXweJQ+7Y9SvGQDeAH8gEzgLLlkNrwpaFtLpxUqHrGWKJHUS8oKtleTznoK1Ck9Es2JTG2Tr4gVHk0OCIfc3hZRQl5Kj7AVi20Tec= \ No newline at end of file + secure: CEIaN/RNCYALwL+QgBhVlyq5DvomyMcmB+gUfdDabxJk55misbIAXkj7l3+1dvq4EeB8Vw3vSKAimfjpj0hGCopOPxPsE5SPYWx3czI7cBPvuu3S4NSmx6WEe+pjI3IexUVQXRLazhvvwB6D/vZnFlr3ECYj59K0fGoYOKW14oG2RLVP7Clx3qoo1O8y7F+Ia6fEp/Q4pvwgFKnUL4hJrCUefJwSKDH8Nxf4FF5U41RLE8Xhdqxo1zbZBpT30gaPERzBnTCO3ko5NIEI/WPruQgcRr/PVDTG1xYZ2XqImDb/fHZKqkOJSoOTH+2U2KBxfXCwLPzkz6CkpJ7v14VL4qoV/F5DA9/fTSB4+B6IWusFF8NhstMmeCw0vkfaO/8WW8VEYHXnlTPFAQZJEiEyIYDcyVnUXur0yFEkvr4ZdGDmUEv/AdClVJ7Ig7T4MF2K66Yqtj930VQhI5PSWMKIWFG+2eboBrmXet+Z+2GRhwCGm5knB4/bcDcg9E80cwUWVol6AxVO07n70Qx57qX9Tvz/Ay9ugtEY+xSDQQ+HkFw62MiPDsNhSFoUD+TNY+SnEe1qnciKhb2/1bNTkKMPjifjJmDWkfC07qrXsDBcj4cIgfj6vh8lBj7U6kg7vCjXeJeljgu0wcTDd+EprDHpfRwkoXi9UsnSw2HXAveZMP4= \ No newline at end of file From 47cf2654ab413e9b98162ad82139409a6b9de8c2 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 6 Nov 2019 15:09:18 -0500 Subject: [PATCH 073/106] Determine EOSIO version same way as CDT. --- .cicd/helpers/dependency-info.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index 940241d56..c0f526ac3 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -23,7 +23,10 @@ else git clone https://github.com/EOSIO/eosio.cdt && cd eosio.cdt git pull && git checkout $CDT_VERSION CDT_COMMIT=$(git rev-parse --verify HEAD) - EOSIO_COMMIT=$(echo $EOSIO_VERSION | sed 's/\//\_/') + cd .. + git clone https://github.com/EOSIO/eos && cd eos + git pull && git checkout $EOSIO_VERSION + EOSIO_COMMIT=$(git rev-parse --verify HEAD) cd .. fi echo "Using eosio ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\"..." From f9a6dea589e624eb277121100d4a86f2a2adfd63 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 7 Nov 2019 10:02:19 -0500 Subject: [PATCH 074/106] gke -> eks --- .cicd/pipeline.yml | 6 +++--- eks | 0 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 eks diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 009fe0ef9..801c8d331 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -7,7 +7,7 @@ steps: tar -pczf build.tar.gz build buildkite-agent artifact upload build.tar.gz agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: "${TIMEOUT:-40}" skip: "$SKIP_UBUNTU_18" @@ -19,7 +19,7 @@ steps: tar -xzf build.tar.gz ./.cicd/test.sh agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: "${TIMEOUT:-10}" skip: "$SKIP_UBUNTU_18" @@ -33,6 +33,6 @@ steps: echo '+++ :javascript: Running test-metrics.js' node --max-old-space-size=32768 test-metrics.js agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: 10 soft_fail: true \ No newline at end of file diff --git a/eks b/eks new file mode 100644 index 000000000..e69de29bb From 0cab4127abfce95450119eb6271d316cc352b9ec Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 7 Nov 2019 10:14:13 -0500 Subject: [PATCH 075/106] gke -> eks --- .cicd/pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 009fe0ef9..801c8d331 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -7,7 +7,7 @@ steps: tar -pczf build.tar.gz build buildkite-agent artifact upload build.tar.gz agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: "${TIMEOUT:-40}" skip: "$SKIP_UBUNTU_18" @@ -19,7 +19,7 @@ steps: tar -xzf build.tar.gz ./.cicd/test.sh agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: "${TIMEOUT:-10}" skip: "$SKIP_UBUNTU_18" @@ -33,6 +33,6 @@ steps: echo '+++ :javascript: Running test-metrics.js' node --max-old-space-size=32768 test-metrics.js agents: - queue: "automation-eos-builder-fleet" + queue: "automation-eks-eos-builder-fleet" timeout: 10 soft_fail: true \ No newline at end of file From 6a0df58abe508acaa5f0909b38737aef2fa6ea0a Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 7 Nov 2019 10:54:17 -0500 Subject: [PATCH 076/106] testers --- .cicd/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 801c8d331..9c9a4ab21 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -19,7 +19,7 @@ steps: tar -xzf build.tar.gz ./.cicd/test.sh agents: - queue: "automation-eks-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: "${TIMEOUT:-10}" skip: "$SKIP_UBUNTU_18" @@ -33,6 +33,6 @@ steps: echo '+++ :javascript: Running test-metrics.js' node --max-old-space-size=32768 test-metrics.js agents: - queue: "automation-eks-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: 10 soft_fail: true \ No newline at end of file From c5432c033689a66725bfcb4f4dafff6fc33d3265 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 7 Nov 2019 10:54:29 -0500 Subject: [PATCH 077/106] testers --- .cicd/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cicd/pipeline.yml b/.cicd/pipeline.yml index 801c8d331..9c9a4ab21 100644 --- a/.cicd/pipeline.yml +++ b/.cicd/pipeline.yml @@ -19,7 +19,7 @@ steps: tar -xzf build.tar.gz ./.cicd/test.sh agents: - queue: "automation-eks-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: "${TIMEOUT:-10}" skip: "$SKIP_UBUNTU_18" @@ -33,6 +33,6 @@ steps: echo '+++ :javascript: Running test-metrics.js' node --max-old-space-size=32768 test-metrics.js agents: - queue: "automation-eks-eos-builder-fleet" + queue: "automation-eks-eos-tester-fleet" timeout: 10 soft_fail: true \ No newline at end of file From e32ad4ad32022a8461596404e491d0985009c241 Mon Sep 17 00:00:00 2001 From: Nathan Pierce Date: Thu, 7 Nov 2019 10:55:28 -0500 Subject: [PATCH 078/106] removed eks file --- eks | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 eks diff --git a/eks b/eks deleted file mode 100644 index e69de29bb..000000000 From 81104b00ff3f10ba6ca9838f5eafa37357049d33 Mon Sep 17 00:00:00 2001 From: arhag Date: Sun, 10 Nov 2019 22:40:28 -0500 Subject: [PATCH 079/106] use authorization of bidder for bidrefund deferred transaction --- contracts/eosio.system/src/name_bidding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/eosio.system/src/name_bidding.cpp b/contracts/eosio.system/src/name_bidding.cpp index d08aed653..4c01f353a 100644 --- a/contracts/eosio.system/src/name_bidding.cpp +++ b/contracts/eosio.system/src/name_bidding.cpp @@ -50,7 +50,7 @@ namespace eosiosystem { } eosio::transaction t; - t.actions.emplace_back( permission_level{get_self(), active_permission}, + t.actions.emplace_back( permission_level{current->high_bidder, active_permission}, get_self(), "bidrefund"_n, std::make_tuple( current->high_bidder, newname ) ); From 428217d95e0ffb3f6c94e798274dc4ee248b3a0c Mon Sep 17 00:00:00 2001 From: arhag Date: Tue, 12 Nov 2019 15:10:08 -0500 Subject: [PATCH 080/106] bump version to v1.8.1 --- CMakeLists.txt | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 129994bb9..ebb9aef32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 8) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) #set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index 38a4d5cea..f3178f535 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.8.0 +## Version : 1.8.1 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 bios, system, msig, wrap (formerly known as sudo) and token contracts. @@ -16,7 +16,7 @@ The following unprivileged contract(s) are also part of the system. Dependencies: * [eosio.cdt v1.6.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.6.3) -* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.5) (optional dependency only needed to build unit tests) +* [eosio v1.8.x](https://github.com/EOSIO/eos/releases/tag/v1.8.6) (optional dependency only needed to build unit tests) To build the contracts follow the instructions in [`Build and deploy` section](./docs/02_build-and-deploy.md). From 533233b10539e347ff4efe44210c57e0b8677bd6 Mon Sep 17 00:00:00 2001 From: arhag Date: Sat, 30 Nov 2019 18:07:41 -0500 Subject: [PATCH 081/106] avoid updating total_activated_stake after activation --- contracts/eosio.system/src/delegate_bandwidth.cpp | 2 +- contracts/eosio.system/src/producer_pay.cpp | 6 +++--- contracts/eosio.system/src/voting.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index e1ecbd1f2..d15a8202a 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -392,7 +392,7 @@ namespace eosiosystem { check( unstake_cpu_quantity >= zero_asset, "must unstake a positive amount" ); check( unstake_net_quantity >= zero_asset, "must unstake a positive amount" ); check( unstake_cpu_quantity.amount + unstake_net_quantity.amount > 0, "must unstake a positive amount" ); - check( _gstate.total_activated_stake >= min_activated_stake, + check( _gstate.thresh_activated_stake_time != time_point(), "cannot undelegate bandwidth until the chain is activated (at least 15% of all tokens participate in voting)" ); changebw( from, receiver, -unstake_net_quantity, -unstake_cpu_quantity, false); diff --git a/contracts/eosio.system/src/producer_pay.cpp b/contracts/eosio.system/src/producer_pay.cpp index cf7e2ddeb..4db2f7740 100644 --- a/contracts/eosio.system/src/producer_pay.cpp +++ b/contracts/eosio.system/src/producer_pay.cpp @@ -21,8 +21,8 @@ namespace eosiosystem { // is eventually completely removed, at which point this line can be removed. _gstate2.last_block_num = timestamp; - /** until activated stake crosses this threshold no new rewards are paid */ - if( _gstate.total_activated_stake < min_activated_stake ) + /** until activation, no new rewards are paid */ + if( _gstate.thresh_activated_stake_time == time_point() ) return; if( _gstate.last_pervote_bucket_fill == time_point() ) /// start the presses @@ -71,7 +71,7 @@ namespace eosiosystem { const auto& prod = _producers.get( owner.value ); check( prod.active(), "producer does not have an active key" ); - check( _gstate.total_activated_stake >= min_activated_stake, + check( _gstate.thresh_activated_stake_time != time_point(), "cannot claim rewards until the chain is activated (at least 15% of all tokens participate in voting)" ); const auto ct = current_time_point(); diff --git a/contracts/eosio.system/src/voting.cpp b/contracts/eosio.system/src/voting.cpp index 95f1dd36a..5386fb502 100644 --- a/contracts/eosio.system/src/voting.cpp +++ b/contracts/eosio.system/src/voting.cpp @@ -188,13 +188,13 @@ namespace eosiosystem { check( !proxy || !voter->is_proxy, "account registered as a proxy is not allowed to use a proxy" ); /** - * The first time someone votes we calculate and set last_vote_weight, since they cannot unstake until - * after total_activated_stake hits threshold, we can use last_vote_weight to determine that this is + * The first time someone votes we calculate and set last_vote_weight. Since they cannot unstake until + * after the chain has been activated, we can use last_vote_weight to determine that this is * their first vote and should consider their stake activated. */ - if( voter->last_vote_weight <= 0.0 ) { + if( _gstate.thresh_activated_stake_time == time_point() && voter->last_vote_weight <= 0.0 ) { _gstate.total_activated_stake += voter->staked; - if( _gstate.total_activated_stake >= min_activated_stake && _gstate.thresh_activated_stake_time == time_point() ) { + if( _gstate.total_activated_stake >= min_activated_stake ) { _gstate.thresh_activated_stake_time = current_time_point(); } } From 2882f5ee09a87412f87c3b0ed1154c3d4ad16e87 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 2 Dec 2019 14:41:15 -0500 Subject: [PATCH 082/106] bump version to v1.8.2 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb9aef32..e21c73d0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 8) -set(VERSION_PATCH 1) +set(VERSION_PATCH 2) #set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index f3178f535..b98bf5db5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.8.1 +## Version : 1.8.2 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 bios, system, msig, wrap (formerly known as sudo) and token contracts. From 1029e1df4c6c465d065a236778d85ef68bdbb3a2 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 13 Nov 2019 17:16:53 -0500 Subject: [PATCH 083/106] REX changes - initial commit --- .../include/eosio.system/eosio.system.hpp | 14 ++++++ contracts/eosio.system/src/eosio.system.cpp | 2 +- contracts/eosio.system/src/rex.cpp | 50 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index a952edd98..2cc9d0c92 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -333,6 +333,17 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; + struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { + uint8_t version = 0; + int64_t current_rate_of_increase = 0; + time_point_sec last_update_time; + std::map return_buckets; + + uint64_t primary_key()const { return 0; } + }; + + typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + // `rex_fund` structure underlying the rex fund table. A rex fund table entry is defined by: // - `version` defaulted to zero, // - `owner` the owner of the rex fund, @@ -443,6 +454,7 @@ namespace eosiosystem { eosio_global_state4 _gstate4; rammarket _rammarket; rex_pool_table _rexpool; + rex_return_pool_table _rexretpool; rex_fund_table _rexfunds; rex_balance_table _rexbalance; rex_order_table _rexorders; @@ -1121,6 +1133,7 @@ namespace eosiosystem { // defined in rex.cpp void runrex( uint16_t max ); + void update_rex_pool(); void update_resource_limits( const name& from, const name& receiver, int64_t delta_net, int64_t delta_cpu ); void check_voting_requirement( const name& owner, const char* error_msg = "must vote for at least 21 producers or for a proxy before buying REX" )const; @@ -1142,6 +1155,7 @@ namespace eosiosystem { static time_point_sec get_rex_maturity(); asset add_to_rex_balance( const name& owner, const asset& payment, const asset& rex_received ); asset add_to_rex_pool( const asset& payment ); + void add_to_rex_return_pool( const asset& fee ); void process_rex_maturities( const rex_balance_table::const_iterator& bitr ); void consolidate_rex_balance( const rex_balance_table::const_iterator& bitr, const asset& rex_in_sell_order ); diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b05c5f011..a6af9e0d0 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -26,11 +26,11 @@ namespace eosiosystem { _global4(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), + _rexretpool(get_self(), get_self().value), _rexfunds(get_self(), get_self().value), _rexbalance(get_self(), get_self().value), _rexorders(get_self(), get_self().value) { - //print( "construct system\n" ); _gstate = _global.exists() ? _global.get() : get_default_parameters(); _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 4a4596e25..c55c798ab 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -513,6 +513,8 @@ namespace eosiosystem { { check( rex_system_initialized(), "rex system not initialized yet" ); + update_rex_pool(); + const auto& pool = _rexpool.begin(); auto process_expired_loan = [&]( auto& idx, const auto& itr ) -> std::pair { @@ -616,6 +618,43 @@ namespace eosiosystem { } + void system_contract::update_rex_pool() + { + const int32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); + const auto time_threshold = ct - eosio::days(num_of_days); + + int64_t change = change_estimate; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + auto& return_buckets = return_pool.return_buckets; + auto iter= return_buckets.begin(); + while ( iter!= return_buckets.begin() && iter->first <= time_threshold ) { + auto next = iter; + ++next; + const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); + const int64_t rate = iter->second; + int64_t surplus = ( uint128_t(overtime) * rate ) / ( num_of_days * seconds_per_day ); + change -= surplus; + return_pool.current_rate_of_increase -= rate; + return_buckets.erase(iter); + iter = next; + } + return_pool.last_update_time = ct; + }); + + if ( change <= 0 ) { + return; + } + + _rexpool.modify(_rexpool.begin(), same_payer, [&](auto& pool) { + pool.total_unlent.amount += change; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + } + template int64_t system_contract::rent_rex( T& table, const name& from, const name& receiver, const asset& payment, const asset& fund ) { @@ -961,6 +1000,17 @@ namespace eosiosystem { return rex_received; } + void system_contract::add_to_rex_return_pool( const asset& fee ) + { + update_rex_pool(); + const uint32_t cts = current_time_point().sec_since_epoch(); + time_point_sec effective_time{ cts - cts % seconds_per_day }; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + return_pool.return_buckets[effective_time] += fee.amount; + return_pool.current_rate_of_increase += fee.amount; + }); + } + /** * @brief Updates owner REX balance upon buying REX tokens * From 4507d1b6753f2fd860829c0f768eda75cbbe576d Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 15 Nov 2019 18:06:42 -0500 Subject: [PATCH 084/106] REX changes --- .../include/eosio.system/eosio.system.hpp | 1 + contracts/eosio.system/src/rex.cpp | 69 +++++++++++++++---- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2cc9d0c92..ec349124b 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,6 +336,7 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; int64_t current_rate_of_increase = 0; + int64_t residue = 0; time_point_sec last_update_time; std::map return_buckets; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index c55c798ab..f9ba8cabe 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -452,15 +452,13 @@ namespace eosiosystem { */ void system_contract::add_loan_to_rex_pool( const asset& payment, int64_t rented_tokens, bool new_loan ) { + add_to_rex_return_pool( payment ); _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& rt ) { // add payment to total_rent rt.total_rent.amount += payment.amount; // move rented_tokens from total_unlent to total_lent rt.total_unlent.amount -= rented_tokens; rt.total_lent.amount += rented_tokens; - // add payment to total_unlent - rt.total_unlent.amount += payment.amount; - rt.total_lendable.amount = rt.total_unlent.amount + rt.total_lent.amount; // increment loan_num if a new loan is being created if ( new_loan ) { rt.loan_num++; @@ -620,18 +618,39 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const int32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); + const int32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + + if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { + return; + } + + if ( _rexretpool.begin()->residue > 0 ) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { + pool.total_unlent.amount += _rexretpool.begin()->residue; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.residue = 0; + }); + } + + if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.last_update_time = ct; + }); + return; + } const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); const auto time_threshold = ct - eosio::days(num_of_days); int64_t change = change_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { auto& return_buckets = return_pool.return_buckets; - auto iter= return_buckets.begin(); - while ( iter!= return_buckets.begin() && iter->first <= time_threshold ) { + auto iter = return_buckets.begin(); + while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); @@ -649,7 +668,7 @@ namespace eosiosystem { return; } - _rexpool.modify(_rexpool.begin(), same_payer, [&](auto& pool) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); @@ -1003,11 +1022,33 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - const uint32_t cts = current_time_point().sec_since_epoch(); - time_point_sec effective_time{ cts - cts % seconds_per_day }; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { - return_pool.return_buckets[effective_time] += fee.amount; - return_pool.current_rate_of_increase += fee.amount; + const uint32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + + if ( _rexretpool.begin() == _rexretpool.end() ) { + _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { + return_pool.last_update_time = ct; + }); + } + + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + time_point_sec effective_time{ cts - cts % seconds_per_day }; + auto& return_buckets = return_pool.return_buckets; + auto& current_rate_of_increase = return_pool.current_rate_of_increase; + auto iter = return_buckets.find( effective_time ); + if ( iter != return_buckets.end() ) { + iter->second += fee.amount; + } else { + int64_t residue = 0; + if ( !return_buckets.empty() ) { + uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / ( num_of_days * seconds_per_day ); + } + return_pool.residue += residue; + current_rate_of_increase += return_buckets.rbegin()->second; + return_buckets[effective_time] = fee.amount; + } }); } From 44f5884824786fcd183199877ebc8e444c0c3068 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 19 Nov 2019 10:23:31 -0500 Subject: [PATCH 085/106] Changes to REX return buckets --- .../include/eosio.system/eosio.system.hpp | 2 ++ contracts/eosio.system/src/rex.cpp | 27 ++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index ec349124b..b8f991734 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -59,6 +59,7 @@ namespace eosiosystem { static constexpr uint32_t seconds_per_year = 52 * 7 * 24 * 3600; static constexpr uint32_t seconds_per_day = 24 * 3600; + static constexpr uint32_t seconds_per_hour = 3600; static constexpr int64_t useconds_per_year = int64_t(seconds_per_year) * 1000'000ll; static constexpr int64_t useconds_per_day = int64_t(seconds_per_day) * 1000'000ll; static constexpr uint32_t blocks_per_day = 2 * seconds_per_day; // half seconds per day @@ -335,6 +336,7 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; + uint8_t hours_per_bucket = 12; int64_t current_rate_of_increase = 0; int64_t residue = 0; time_point_sec last_update_time; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index f9ba8cabe..58937b59a 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,8 +618,8 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const int32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); + constexpr int32_t total_duration = 30 * seconds_per_day; + const time_point_sec ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; @@ -641,10 +641,10 @@ namespace eosiosystem { }); return; } - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); - const auto time_threshold = ct - eosio::days(num_of_days); + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - total_duration }; int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { @@ -655,7 +655,7 @@ namespace eosiosystem { ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); const int64_t rate = iter->second; - int64_t surplus = ( uint128_t(overtime) * rate ) / ( num_of_days * seconds_per_day ); + const int64_t surplus = ( uint128_t(overtime) * rate ) / total_duration; change -= surplus; return_pool.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -1022,9 +1022,9 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - const uint32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + constexpr uint32_t total_duration = 30 * seconds_per_day; + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { @@ -1032,8 +1032,11 @@ namespace eosiosystem { }); } + const uint8_t hours_per_bucket = _rexretpool.begin()->hours_per_bucket; + const uint32_t bucket_interval = hours_per_bucket * seconds_per_hour; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - time_point_sec effective_time{ cts - cts % seconds_per_day }; + time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; auto& return_buckets = return_pool.return_buckets; auto& current_rate_of_increase = return_pool.current_rate_of_increase; auto iter = return_buckets.find( effective_time ); @@ -1043,7 +1046,7 @@ namespace eosiosystem { int64_t residue = 0; if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / ( num_of_days * seconds_per_day ); + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; } return_pool.residue += residue; current_rate_of_increase += return_buckets.rbegin()->second; From be375971b8850f0f436c9f5f577cfe0033048d70 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 19 Nov 2019 18:26:40 -0500 Subject: [PATCH 086/106] REX changes testing --- contracts/eosio.system/src/rex.cpp | 8 ++++---- tests/eosio.system_tester.hpp | 21 +++++++++++++++++++++ tests/eosio.system_tests.cpp | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 58937b59a..aa268529a 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -1032,8 +1032,7 @@ namespace eosiosystem { }); } - const uint8_t hours_per_bucket = _rexretpool.begin()->hours_per_bucket; - const uint32_t bucket_interval = hours_per_bucket * seconds_per_hour; + const uint32_t bucket_interval = _rexretpool.begin()->hours_per_bucket * seconds_per_hour; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; @@ -1047,9 +1046,10 @@ namespace eosiosystem { if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; + current_rate_of_increase += return_buckets.rbegin()->second; } - return_pool.residue += residue; - current_rate_of_increase += return_buckets.rbegin()->second; + return_pool.residue += residue; + // current_rate_of_increase += return_buckets.rbegin()->second; return_buckets[effective_time] = fee.amount; } }); diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 179d4b0fa..acf3b6c60 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -638,6 +638,27 @@ class eosio_system_tester : public TESTER { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_pool", data, abi_serializer_max_time ); } + fc::variant get_rex_return_pool() const { + vector data; + const auto& db = control->db(); + namespace chain = eosio::chain; + const auto* t_id = db.find( boost::make_tuple( config::system_account_name, config::system_account_name, N(rexretpool) ) ); + if ( !t_id ) { + return fc::variant(); + } + + const auto& idx = db.get_index(); + + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, 0 ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || 0 != itr->primary_key ) { + return fc::variant(); + } + + data.resize( itr->value.size() ); + memcpy( data.data(), itr->value.data(), data.size() ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_pool", data, abi_serializer_max_time ); + } + void setup_rex_accounts( const std::vector& accounts, const asset& init_balance, const asset& net = core_sym::from_string("80.0000"), diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 1eed42e40..71239404f 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3613,6 +3613,7 @@ BOOST_FIXTURE_TEST_CASE( rex_auth, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE( buy_sell_rex, eosio_system_tester ) try { const int64_t ratio = 10000; @@ -3850,13 +3851,15 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( ratio * init_tot_lendable.get_amount(), rex_pool["total_rex"].as().get_amount() ); BOOST_REQUIRE_EQUAL( rex_pool["total_rex"].as(), get_rex_balance(alice) ); + BOOST_REQUIRE( get_rex_return_pool().is_null() ); + { // bob rents cpu for carol const asset fee = core_sym::from_string("17.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, carol, fee ) ); BOOST_REQUIRE_EQUAL( init_balance - fee, get_rex_fund(bob) ); rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( init_tot_lendable + fee, rex_pool["total_lendable"].as() ); // 65 + 17 + BOOST_REQUIRE_EQUAL( init_tot_lendable, rex_pool["total_lendable"].as() ); // 65 BOOST_REQUIRE_EQUAL( init_tot_rent + fee, rex_pool["total_rent"].as() ); // 100 + 17 int64_t expected_total_lent = bancor_convert( init_tot_rent.get_amount(), init_tot_unlent.get_amount(), fee.get_amount() ); BOOST_REQUIRE_EQUAL( expected_total_lent, @@ -3864,6 +3867,12 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( rex_pool["total_lent"].as() + rex_pool["total_unlent"].as(), rex_pool["total_lendable"].as() ); + auto rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE( !rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + + // test that carol's resource limits have been updated properly BOOST_REQUIRE_EQUAL( expected_total_lent, get_cpu_limit( carol ) - init_cpu_limit ); BOOST_REQUIRE_EQUAL( 0, get_net_limit( carol ) - init_net_limit ); @@ -3878,6 +3887,12 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { produce_block( fc::days(20) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); BOOST_REQUIRE_EQUAL( success(), cancelrexorder( alice ) ); + + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE( !rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); From d6de1a53e2e4132a84c526871d578aa53c1d9259 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Thu, 21 Nov 2019 09:51:50 -0500 Subject: [PATCH 087/106] REX changes testing - 2 --- .../include/eosio.system/eosio.system.hpp | 4 +- contracts/eosio.system/src/rex.cpp | 46 +++++++++++-------- tests/eosio.system_tests.cpp | 11 +++-- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index b8f991734..df19f8233 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,12 +336,14 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; - uint8_t hours_per_bucket = 12; int64_t current_rate_of_increase = 0; int64_t residue = 0; time_point_sec last_update_time; std::map return_buckets; + static constexpr uint32_t total_duration = 30 * seconds_per_day; + static constexpr uint8_t hours_per_bucket = 12; + uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index aa268529a..7d4951a1b 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,8 +618,7 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - constexpr int32_t total_duration = 30 * seconds_per_day; - const time_point_sec ct = current_time_point(); + const time_point_sec ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; @@ -634,17 +633,24 @@ namespace eosiosystem { return_pool.residue = 0; }); } - + /* if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { return_pool.last_update_time = ct; }); return; } - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + */ + if ( _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.current_rate_of_increase += return_pool.return_buckets.rbegin()->second; + }); + } + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / total_duration; - const time_point_sec time_threshold{ ct.sec_since_epoch() - total_duration }; + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { @@ -655,7 +661,7 @@ namespace eosiosystem { ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate ) / total_duration; + const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; change -= surplus; return_pool.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -1022,35 +1028,39 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - constexpr uint32_t total_duration = 30 * seconds_per_day; - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; + const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { - return_pool.last_update_time = ct; + return_pool.last_update_time = effective_time; }); } - const uint32_t bucket_interval = _rexretpool.begin()->hours_per_bucket * seconds_per_hour; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; auto& return_buckets = return_pool.return_buckets; auto& current_rate_of_increase = return_pool.current_rate_of_increase; auto iter = return_buckets.find( effective_time ); if ( iter != return_buckets.end() ) { iter->second += fee.amount; } else { + // create a new bucket + // but first process the previous bucket if it exists int64_t residue = 0; if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; - current_rate_of_increase += return_buckets.rbegin()->second; + if ( interval < rex_return_pool::total_duration ) { + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / rex_return_pool::total_duration; + current_rate_of_increase += return_buckets.rbegin()->second; + } else { + residue = return_buckets.rbegin()->second; + // erase rbegin + } } return_pool.residue += residue; - // current_rate_of_increase += return_buckets.rbegin()->second; - return_buckets[effective_time] = fee.amount; + return_buckets.emplace( effective_time, fee.amount ); } }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 71239404f..d1ee12ff4 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3890,14 +3890,17 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); - BOOST_REQUIRE_EQUAL( init_balance + fee, get_rex_fund(alice) ); + auto expected_rex_fund = (init_balance + fee).get_amount(); + auto actual_rex_fund = get_rex_fund(alice).get_amount(); + BOOST_REQUIRE_EQUAL( true, within_one( expected_rex_fund, actual_rex_fund ) ); + BOOST_REQUIRE( actual_rex_fund <= expected_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -3955,7 +3958,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_sell_rex, eosio_system_tester ) try { const asset fee = core_sym::from_string("7.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, carol, fee ) ); rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( init_tot_lendable + fee, rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( init_tot_lendable, rex_pool["total_lendable"].as() ); BOOST_REQUIRE_EQUAL( init_tot_rent + fee, rex_pool["total_rent"].as() ); produce_block( fc::days(5) ); From 43861c68151b0c71ba19a07274f495f0b37bee53 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 27 Nov 2019 23:27:34 -0700 Subject: [PATCH 088/106] REX changes - fix unit tests --- .../include/eosio.system/eosio.system.hpp | 3 +- contracts/eosio.system/src/rex.cpp | 79 ++++++------------- tests/eosio.system_tests.cpp | 70 ++++++++++------ 3 files changed, 69 insertions(+), 83 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index df19f8233..902fb62a3 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,9 +336,8 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; - int64_t current_rate_of_increase = 0; - int64_t residue = 0; time_point_sec last_update_time; + int64_t current_rate_of_increase = 0; std::map return_buckets; static constexpr uint32_t total_duration = 30 * seconds_per_day; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 7d4951a1b..86b33c619 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -624,50 +624,40 @@ namespace eosiosystem { return; } - if ( _rexretpool.begin()->residue > 0 ) { - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { - pool.total_unlent.amount += _rexretpool.begin()->residue; - pool.total_lendable = pool.total_unlent + pool.total_lent; - }); - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.residue = 0; - }); - } - /* - if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.last_update_time = ct; - }); - return; - } - */ - if ( _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.current_rate_of_increase += return_pool.return_buckets.rbegin()->second; + const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() + && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first + && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; + int64_t new_bucket_overestimate = 0; + if ( new_return_bucket ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; + const uint32_t dt = rp.return_buckets.rbegin()->first.sec_since_epoch() - rp.last_update_time.sec_since_epoch(); + new_bucket_overestimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration + - new_bucket_overestimate; const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; int64_t change = change_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - auto& return_buckets = return_pool.return_buckets; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); + const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); const int64_t rate = iter->second; const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; - change -= surplus; - return_pool.current_rate_of_increase -= rate; + change -= surplus; + rp.current_rate_of_increase -= rate; return_buckets.erase(iter); iter = next; } - return_pool.last_update_time = ct; + rp.last_update_time = ct; }); if ( change <= 0 ) { @@ -1029,39 +1019,18 @@ namespace eosiosystem { { update_rex_pool(); - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + const uint32_t cts = current_time_point().sec_since_epoch(); const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; + if ( _rexretpool.begin() == _rexretpool.end() ) { - _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { - return_pool.last_update_time = effective_time; + _rexretpool.emplace( get_self(), [&]( auto& rp ) { + rp.last_update_time = effective_time; }); } - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - auto& return_buckets = return_pool.return_buckets; - auto& current_rate_of_increase = return_pool.current_rate_of_increase; - auto iter = return_buckets.find( effective_time ); - if ( iter != return_buckets.end() ) { - iter->second += fee.amount; - } else { - // create a new bucket - // but first process the previous bucket if it exists - int64_t residue = 0; - if ( !return_buckets.empty() ) { - uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - if ( interval < rex_return_pool::total_duration ) { - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / rex_return_pool::total_duration; - current_rate_of_increase += return_buckets.rbegin()->second; - } else { - residue = return_buckets.rbegin()->second; - // erase rbegin - } - } - return_pool.residue += residue; - return_buckets.emplace( effective_time, fee.amount ); - } + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.return_buckets[effective_time] += fee.amount; }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index d1ee12ff4..399c3d169 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3869,9 +3869,7 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); // test that carol's resource limits have been updated properly BOOST_REQUIRE_EQUAL( expected_total_lent, get_cpu_limit( carol ) - init_cpu_limit ); @@ -3890,7 +3888,6 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); @@ -4018,30 +4015,31 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("20000.0000") ) ); } - const asset rent_payment = core_sym::from_string("40000.0000"); + produce_block( fc::days(25) ); + const asset rent_payment = core_sym::from_string("40000.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( frank, frank, rent_payment, rent_payment ) ); + produce_block( fc::days(4) ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); + const auto init_rex_pool = get_rex_pool(); const int64_t total_lendable = init_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = init_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_alice_rex.get_amount()) * total_lendable ) / total_rex; - produce_block( fc::days(5) ); - BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol(SY(4,REX)) ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); - produce_block( fc::days(5) ); - init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( carol, get_rex_balance(carol) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); - + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_balance(bob) ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_balance(carol) ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_balance(alice) ); @@ -4058,7 +4056,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); // wait for 30 days minus 1 hour - produce_block( fc::hours(19*24 + 23) ); + produce_block( fc::hours(23) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); BOOST_REQUIRE_EQUAL( true, get_rex_order(bob)["is_open"].as() ); @@ -4081,21 +4079,28 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { } { + BOOST_REQUIRE_EQUAL( false, get_rex_order(bob)["is_open"].as() ); + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_order(bob)["rex_requested"].as() ); + BOOST_TEST_REQUIRE ( 0 < get_rex_order(bob)["proceeds"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_order(alice)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(alice)["proceeds"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( false, get_rex_order(bob)["is_open"].as() ); - BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_order(bob)["rex_requested"].as() ); - BOOST_REQUIRE ( 0 < get_rex_order(bob)["proceeds"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( true, get_rex_order(carol)["is_open"].as() ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_order(carol)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("rex loans are currently not available"), rentcpu( frank, frank, core_sym::from_string("1.0000") ) ); } + produce_blocks(2); + produce_block( fc::hours(13) ); + produce_blocks(2); + produce_block( fc::days(30) ); + produce_blocks(2); + { auto trace1 = base_tester::push_action( config::system_account_name, N(updaterex), bob, mvo()("owner", bob) ); auto trace2 = base_tester::push_action( config::system_account_name, N(updaterex), carol, mvo()("owner", carol) ); @@ -4223,7 +4228,8 @@ BOOST_FIXTURE_TEST_CASE( rex_loans, eosio_system_tester ) try { } // wait for 30 days, frank's loan will be renewed at the current price - produce_block( fc::hours(30*24 + 1) ); + produce_block( fc::minutes(30*24*60 - 1) ); + BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); rex_pool = get_rex_pool(); { int64_t unlent_tokens = bancor_convert( rex_pool["total_unlent"].as().get_amount(), @@ -4235,6 +4241,8 @@ BOOST_FIXTURE_TEST_CASE( rex_loans, eosio_system_tester ) try { payment.get_amount() ); } + produce_block( fc::minutes(2) ); + BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset::from_string("1.0000 REX") ) ); loan_info = get_cpu_loan(1); @@ -4723,15 +4731,17 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const int64_t init_stake = get_voter_info( alice )["staked"].as(); + // alice buys rex const asset payment = core_sym::from_string("25000.0000"); BOOST_REQUIRE_EQUAL( success(), buyrex( alice, payment ) ); BOOST_REQUIRE_EQUAL( payment, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake ); + // emily rents cpu const asset fee = core_sym::from_string("50.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, fee ) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - BOOST_REQUIRE_EQUAL( payment + fee, get_rex_vote_stake(alice) ); + BOOST_REQUIRE_EQUAL( payment, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info( alice )["staked"].as() - init_stake ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers @@ -4751,9 +4761,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 20) ) ); + vote( alice, { producer_names.begin(), producer_names.begin() + 20 } ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4761,23 +4771,25 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - produce_block( fc::days(20) ); + produce_block( fc::days(10) ); BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); + BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); + produce_block( fc::hours(19 * 24 + 23) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); const int64_t total_lendable = current_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = current_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_rex.get_amount()) * total_lendable ) / total_rex; - produce_block( fc::days(5) ); const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_REQUIRE_EQUAL( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ); + BOOST_TEST_REQUIRE( within_one( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ) ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4827,18 +4839,20 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_REQUIRE_EQUAL( purchase, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( purchase.get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); const auto init_rex_pool = get_rex_pool(); const asset rent = core_sym::from_string("25.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + + produce_block( fc::days(31) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const auto curr_rex_pool = get_rex_pool(); BOOST_REQUIRE_EQUAL( curr_rex_pool["total_lendable"].as(), init_rex_pool["total_lendable"].as() + rent ); - BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_REQUIRE_EQUAL( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == @@ -4850,11 +4864,15 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes const asset to_cpu_stake = core_sym::from_string("40.0000"); transfer( config::system_account_name, alice, to_net_stake + to_cpu_stake, config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + produce_block( fc::hours(30 * 24 + 12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + produce_block( fc::hours(30 * 24 + 12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + rent) == From 6b6898c6416746dc9fc74ed25937cb9acd3370d0 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 29 Nov 2019 14:49:48 -0700 Subject: [PATCH 089/106] REX changes - distribute ramfee and namebids --- contracts/eosio.system/src/rex.cpp | 26 +++++++------- tests/eosio.system_tests.cpp | 54 +++++++++++++++++++----------- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 86b33c619..b33e597be 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -624,25 +624,25 @@ namespace eosiosystem { return; } + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; - int64_t new_bucket_overestimate = 0; + int64_t new_bucket_estimate = 0; if ( new_return_bucket ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint32_t dt = rp.return_buckets.rbegin()->first.sec_since_epoch() - rp.last_update_time.sec_since_epoch(); - new_bucket_overestimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; + const uint32_t dt = ct.sec_since_epoch() - rp.return_buckets.rbegin()->first.sec_since_epoch(); + new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration - - new_bucket_overestimate; - const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + int64_t change = change_estimate + new_bucket_estimate; - int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); @@ -651,7 +651,8 @@ namespace eosiosystem { ++next; const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; + const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) + / rex_return_pool::total_duration; change -= surplus; rp.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -872,10 +873,7 @@ namespace eosiosystem { { #if CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX if ( rex_available() ) { - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& rp ) { - rp.total_unlent.amount += amount.amount; - rp.total_lendable.amount += amount.amount; - }); + add_to_rex_return_pool( amount ); // inline transfer to rex_account token::transfer_action transfer_act{ token_account, { from, active_permission } }; transfer_act.send( from, rex_account, amount, diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 399c3d169..f220bba16 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -27,7 +27,8 @@ using namespace eosio_system; BOOST_AUTO_TEST_SUITE(eosio_system_tests) -bool within_one(int64_t a, int64_t b) { return std::abs(a - b) <= 1; } +bool within_error(int64_t a, int64_t b, int64_t err) { return std::abs(a - b) <= err; }; +bool within_one(int64_t a, int64_t b) { return within_error(a, b, 1); } BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { @@ -3896,8 +3897,8 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); auto expected_rex_fund = (init_balance + fee).get_amount(); auto actual_rex_fund = get_rex_fund(alice).get_amount(); - BOOST_REQUIRE_EQUAL( true, within_one( expected_rex_fund, actual_rex_fund ) ); - BOOST_REQUIRE( actual_rex_fund <= expected_rex_fund ); + BOOST_REQUIRE_EQUAL( true, within_error( expected_rex_fund, actual_rex_fund, 2 ) ); + BOOST_TEST_REQUIRE( actual_rex_fund <= expected_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -4327,12 +4328,20 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( get_balance( N(eosio.rex) ), cur_rex_balance + core_sym::from_string("0.3500") ); cur_rex_balance = get_balance( N(eosio.rex) ); + + produce_blocks( 1 ); + produce_block( fc::hours(30*24 + 12) ); + produce_blocks( 1 ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); auto cur_rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( cur_rex_balance, cur_rex_pool["total_unlent"].as() ); - BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["total_lent"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, cur_rex_pool["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["namebid_proceeds"].as().get_amount() ); + BOOST_TEST_REQUIRE( within_one( cur_rex_balance.get_amount(), cur_rex_pool["total_unlent"].as().get_amount() ) ); + BOOST_TEST_REQUIRE( cur_rex_balance >= cur_rex_pool["total_unlent"].as() ); + BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["total_lent"].as().get_amount() ); + BOOST_TEST_REQUIRE( within_one( cur_rex_balance.get_amount(), cur_rex_pool["total_lendable"].as().get_amount() ) ); + BOOST_TEST_REQUIRE( cur_rex_balance >= cur_rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["namebid_proceeds"].as().get_amount() ); // required for closing namebids cross_15_percent_threshold(); @@ -4354,8 +4363,14 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_balance( N(eosio.names) ).get_amount() ); cur_rex_balance = get_balance( N(eosio.rex) ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_unlent"].as() ); + produce_block( fc::hours(30*24 + 13) ); + produce_blocks( 1 ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); + + BOOST_TEST_REQUIRE( within_error( cur_rex_balance.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 4 ) ); + BOOST_TEST_REQUIRE( cur_rex_balance.get_amount() >= get_rex_pool()["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), get_rex_pool()["total_unlent"].as() ); } FC_LOG_AND_RETHROW() @@ -4789,7 +4804,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_TEST_REQUIRE( within_one( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ) ); + BOOST_TEST_REQUIRE( within_error( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount(), 2 ) ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4804,7 +4819,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_test::tolerance(1e-10) ) try { +BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_test::tolerance(1e-8) ) try { cross_15_percent_threshold(); @@ -4850,11 +4865,12 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const auto curr_rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( curr_rex_pool["total_lendable"].as(), init_rex_pool["total_lendable"].as() + rent ); + BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), + init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); - BOOST_REQUIRE_EQUAL( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); - BOOST_REQUIRE_EQUAL( purchase + rent, get_rex_vote_stake(alice) ); + BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); + BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == @@ -4864,18 +4880,18 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes const asset to_cpu_stake = core_sym::from_string("40.0000"); transfer( config::system_account_name, alice, to_net_stake + to_cpu_stake, config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); - produce_block( fc::hours(30 * 24 + 12) ); + produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); + BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 2 ) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); - produce_block( fc::hours(30 * 24 + 12) ); + produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); - BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + rent) == + BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 3 ) ); + BOOST_TEST_REQUIRE ( stake2votes(init_stake + get_rex_vote_stake(alice) ) == get_producer_info(producer_names[0])["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() From 048753ca81b6546075feaea0156f3a4aa4c555b2 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Sun, 1 Dec 2019 23:28:36 -0500 Subject: [PATCH 090/106] REX changes - more testing --- tests/eosio.system_tests.cpp | 105 +++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index f220bba16..31f9a9b6b 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5157,6 +5157,111 @@ BOOST_FIXTURE_TEST_CASE( b1_vesting, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { + + BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); + + const asset init_balance = core_sym::from_string("100000.0000"); + const std::vector accounts = { N(aliceaccount), N(bobbyaccount) }; + account_name alice = accounts[0], bob = accounts[1]; + setup_rex_accounts( accounts, init_balance ); + + const asset payment = core_sym::from_string("100000.0000"); + { + BOOST_REQUIRE_EQUAL( success(), buyrex( alice, payment ) ); + auto rex_pool = get_rex_pool(); + BOOST_REQUIRE_EQUAL( payment, rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( payment, rex_pool["total_unlent"].as() ); + + BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); + } + + { + const asset fee = core_sym::from_string("30.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + auto rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + + produce_block( fc::hours(12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + + uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t expected = payment.get_amount() + change; + + auto rex_pool = get_rex_pool(); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); + + produce_blocks( 1 ); + produce_block( fc::days(25) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t2 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600); + expected = payment.get_amount() + change; + + rex_pool = get_rex_pool(); + BOOST_TEST_REQUIRE( within_one( expected, rex_pool["total_lendable"].as().get_amount() ) ); + + produce_blocks( 1 ); + produce_block( fc::days(5) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + + rex_pool = get_rex_pool(); + expected = payment.get_amount() + fee.get_amount(); + BOOST_TEST_REQUIRE( within_error( expected, rex_pool["total_lendable"].as().get_amount(), 2 ) ); + BOOST_TEST_REQUIRE( expected >= rex_pool["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( rex_pool["total_lendable"].as(), + rex_pool["total_unlent"].as() ); + } + + produce_block( fc::hours(1) ); + + { + const asset init_lendable = get_rex_pool()["total_lendable"].as(); + const asset fee = core_sym::from_string("15.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + auto rex_return_pool = get_rex_return_pool(); + uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + produce_block( fc::hours(1) ); + BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( t0 + 3600, t1 ); + + produce_block( fc::hours(12) ); + BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + produce_block( fc::hours(8) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + + produce_block( fc::days(30) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_TEST_REQUIRE( (init_lendable + fee + fee).get_amount() < get_rex_pool()["total_lendable"].as().get_amount() ); + + produce_block( fc::days(1) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), + get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); + } + +} FC_LOG_AND_RETHROW() + + BOOST_AUTO_TEST_CASE( setabi_bios ) try { validating_tester t( validating_tester::default_config() ); t.execute_setup_policy( setup_policy::preactivate_feature_only ); From 2c91b6dab188c1b93ac0adfc573223b4259d88a3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 01:06:15 -0500 Subject: [PATCH 091/106] REX changes - unlent lower bound --- contracts/eosio.system/src/rex.cpp | 2 +- tests/eosio.system_tests.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index b33e597be..774f88162 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -733,7 +733,7 @@ namespace eosiosystem { asset stake_change( 0, core_symbol() ); bool success = false; - const int64_t unlent_lower_bound = ( uint128_t(2) * rexitr->total_lent.amount ) / 10; + const int64_t unlent_lower_bound = rexitr->total_lent.amount / 10; const int64_t available_unlent = rexitr->total_unlent.amount - unlent_lower_bound; // available_unlent <= 0 is possible if ( proceeds.amount <= available_unlent ) { const int64_t init_vote_stake_amount = bitr->vote_stake.amount; diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 31f9a9b6b..4e7219d75 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3993,8 +3993,8 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { setup_rex_accounts( accounts, init_balance ); const auto purchase1 = core_sym::from_string("50000.0000"); - const auto purchase2 = core_sym::from_string("235500.0000"); - const auto purchase3 = core_sym::from_string("234500.0000"); + const auto purchase2 = core_sym::from_string("105500.0000"); + const auto purchase3 = core_sym::from_string("104500.0000"); const auto init_stake = get_voter_info(alice)["staked"].as(); BOOST_REQUIRE_EQUAL( success(), buyrex( alice, purchase1) ); BOOST_REQUIRE_EQUAL( success(), buyrex( bob, purchase2) ); @@ -4013,12 +4013,12 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_sym::from_string("20000.0000"), get_rex_pool()["total_rent"].as() ); for (uint8_t i = 0; i < 4; ++i) { - BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("20000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("12000.0000") ) ); } produce_block( fc::days(25) ); - const asset rent_payment = core_sym::from_string("40000.0000"); + const asset rent_payment = core_sym::from_string("46000.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( frank, frank, rent_payment, rent_payment ) ); produce_block( fc::days(4) ); @@ -4675,7 +4675,7 @@ BOOST_FIXTURE_TEST_CASE( rex_savings, eosio_system_tester ) try { produce_block( fc::days(5) ); - BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, core_sym::from_string("2000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, core_sym::from_string("3000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 9 * rex_bucket_amount / 10, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( rex_bucket, get_rex_balance( alice ) ); BOOST_REQUIRE_EQUAL( success(), mvtosavings( alice, asset( rex_bucket_amount / 10, rex_sym ) ) ); @@ -4948,11 +4948,11 @@ BOOST_FIXTURE_TEST_CASE( rex_lower_bound, eosio_system_tester ) try { const int64_t tot_lent = rex_pool["total_lent"].as().get_amount(); const int64_t tot_lendable = rex_pool["total_lendable"].as().get_amount(); double rex_per_eos = double(tot_rex) / double(tot_lendable); - int64_t sell_amount = rex_per_eos * ( tot_unlent - 0.19 * tot_lent ); + int64_t sell_amount = rex_per_eos * ( tot_unlent - 0.09 * tot_lent ); produce_block( fc::days(5) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( sell_amount, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( success(), cancelrexorder( alice ) ); - sell_amount = rex_per_eos * ( tot_unlent - 0.2 * tot_lent ); + sell_amount = rex_per_eos * ( tot_unlent - 0.1 * tot_lent ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( sell_amount, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("no sellrex order is scheduled"), cancelrexorder( alice ) ); From 07584f7ace34cfc92ed99ce31570c6c08b1957f3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 17:32:23 -0500 Subject: [PATCH 092/106] REX changes - use microseconds instead of seconds --- .../include/eosio.system/eosio.system.hpp | 13 ++++---- contracts/eosio.system/src/rex.cpp | 20 ++++++------ tests/eosio.system_tests.cpp | 31 ++++++++++--------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 902fb62a3..be473fcfc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -62,6 +62,7 @@ namespace eosiosystem { static constexpr uint32_t seconds_per_hour = 3600; static constexpr int64_t useconds_per_year = int64_t(seconds_per_year) * 1000'000ll; static constexpr int64_t useconds_per_day = int64_t(seconds_per_day) * 1000'000ll; + static constexpr int64_t useconds_per_hour = int64_t(seconds_per_hour) * 1000'000ll; static constexpr uint32_t blocks_per_day = 2 * seconds_per_day; // half seconds per day static constexpr int64_t min_activated_stake = 150'000'000'0000; @@ -335,13 +336,13 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { - uint8_t version = 0; - time_point_sec last_update_time; - int64_t current_rate_of_increase = 0; - std::map return_buckets; + uint8_t version = 0; + time_point last_update_time; + int64_t current_rate_of_increase = 0; + std::map return_buckets; - static constexpr uint32_t total_duration = 30 * seconds_per_day; - static constexpr uint8_t hours_per_bucket = 12; + static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 774f88162..5bf02df16 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,16 +618,16 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const time_point_sec ct = current_time_point(); + const time_point ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; - const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const uint64_t time_interval = ct.time_since_epoch().count() - _rexretpool.begin()->last_update_time.time_since_epoch().count(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first @@ -636,7 +636,7 @@ namespace eosiosystem { if ( new_return_bucket ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint32_t dt = ct.sec_since_epoch() - rp.return_buckets.rbegin()->first.sec_since_epoch(); + const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } @@ -649,7 +649,7 @@ namespace eosiosystem { while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); + const uint64_t overtime = ct.time_since_epoch().count() - ( iter->first.time_since_epoch().count() + rex_return_pool::total_duration ); const int64_t rate = iter->second; const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) / rex_return_pool::total_duration; @@ -1017,9 +1017,9 @@ namespace eosiosystem { { update_rex_pool(); - const uint32_t cts = current_time_point().sec_since_epoch(); - const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; - const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; + const int64_t cts = current_time_point().time_since_epoch().count(); + const int64_t bucket_interval = rex_return_pool::hours_per_bucket * useconds_per_hour; + const time_point effective_time{ eosio::microseconds{cts - cts % bucket_interval + bucket_interval} }; if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 4e7219d75..c3a79dc71 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4024,23 +4024,24 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { produce_block( fc::days(4) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); - + const auto init_rex_pool = get_rex_pool(); const int64_t total_lendable = init_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = init_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_alice_rex.get_amount()) * total_lendable ) / total_rex; - BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol(SY(4,REX)) ) ) ); + BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol{SY(4,REX)} ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); - BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); - BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); + // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); + // BOOST_REQUIRE_EQUAL( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ); + // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( carol, get_rex_balance(carol) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); - + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_balance(bob) ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_balance(carol) ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_balance(alice) ); @@ -4056,7 +4057,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_order(carol)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); - // wait for 30 days minus 1 hour + // wait for a total of 30 days minus 1 hour produce_block( fc::hours(23) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); @@ -5182,15 +5183,15 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - produce_block( fc::hours(12) ); + produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); int64_t expected = payment.get_amount() + change; auto rex_pool = get_rex_pool(); @@ -5201,8 +5202,8 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t2 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t t2 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); expected = payment.get_amount() + change; rex_pool = get_rex_pool(); @@ -5230,13 +5231,13 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { const asset fee = core_sym::from_string("15.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); - uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); produce_block( fc::hours(1) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - BOOST_REQUIRE_EQUAL( t0 + 3600, t1 ); + int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); From e7b7b0c7ea8c581eb5494347fd16e584a4dcfbfa Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 18:12:17 -0500 Subject: [PATCH 093/106] REX changes - comments --- .../eosio.system/include/eosio.system/eosio.system.hpp | 7 ++++++- contracts/eosio.system/src/rex.cpp | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index be473fcfc..61d18ee8b 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -335,13 +335,18 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; + // `rex_return_pool` structure underlying the rex return pool table. A rex return pool table entry is defined by: + // - `version` defaulted to zero, + // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, + // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, + // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point last_update_time; int64_t current_rate_of_increase = 0; std::map return_buckets; - static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr int64_t total_duration = 30 * useconds_per_day; static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 5bf02df16..4aeef7d5e 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -616,6 +616,9 @@ namespace eosiosystem { } + /** + * @brief Adds returns from the REX return pool to the REX pool + */ void system_contract::update_rex_pool() { const time_point ct = current_time_point(); @@ -1013,6 +1016,11 @@ namespace eosiosystem { return rex_received; } + /** + * @brief Adds an amount of core tokens to the REX return pool + * + * @param fee - amount to be added + */ void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); From 854a6239bcf8c8d1a0880ed7faf2c28d6c0448d3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 9 Dec 2019 16:16:12 -0500 Subject: [PATCH 094/106] REX changes - time interval between REX pool updates --- .../include/eosio.system/eosio.system.hpp | 6 ++++ contracts/eosio.system/src/rex.cpp | 11 ++++++- tests/eosio.system_tests.cpp | 32 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 61d18ee8b..95108dc9c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -339,14 +339,20 @@ namespace eosiosystem { // - `version` defaulted to zero, // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, + // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, + // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; + time_point last_update_time; int64_t current_rate_of_increase = 0; + int64_t cummulative_proceeds = 0; + int64_t proceeds = 0; std::map return_buckets; static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr int64_t dist_interval = 10 * 60 * 1000'000; static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 4aeef7d5e..d47017f40 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -623,7 +623,8 @@ namespace eosiosystem { { const time_point ct = current_time_point(); - if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { + if ( _rexretpool.begin() == _rexretpool.end() || + ct < _rexretpool.begin()->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { return; } @@ -672,6 +673,9 @@ namespace eosiosystem { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.cummulative_proceeds += change; + }); } template @@ -1032,6 +1036,11 @@ namespace eosiosystem { if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { rp.last_update_time = effective_time; + rp.proceeds += fee.amount; + }); + } else { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.proceeds += fee.amount; }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index c3a79dc71..63e0f5f91 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5183,6 +5183,7 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); produce_block( fc::hours(13) ); @@ -5215,6 +5216,7 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); rex_pool = get_rex_pool(); expected = payment.get_amount() + fee.get_amount(); @@ -5236,11 +5238,15 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 2, rex_return_pool["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::hours(8) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); @@ -5256,10 +5262,36 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); } + { + const asset fee = core_sym::from_string("25.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + produce_block( fc::hours(13) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_0 = get_rex_pool(); + auto rex_return_pool_0 = get_rex_return_pool(); + produce_block( fc::minutes(9) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_1 = get_rex_pool(); + auto rex_return_pool_1 = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_update_time"].as().time_since_epoch().count(), + rex_return_pool_1["last_update_time"].as().time_since_epoch().count()); + BOOST_REQUIRE_EQUAL( rex_pool_0["total_lendable"].as(), + rex_pool_1["total_lendable"].as()); + produce_block( fc::minutes(1) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_2 = get_rex_pool(); + auto rex_return_pool_2 = get_rex_return_pool(); + BOOST_TEST_REQUIRE( rex_return_pool_1["last_update_time"].as().time_since_epoch().count() < + rex_return_pool_2["last_update_time"].as().time_since_epoch().count()); + BOOST_TEST_REQUIRE( rex_pool_1["total_lendable"].as().get_amount() < + rex_pool_2["total_lendable"].as().get_amount()); + } + } FC_LOG_AND_RETHROW() From 4ef78d7201a80298c31a1fc23e9dba34c43036ec Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 9 Dec 2019 17:06:53 -0500 Subject: [PATCH 095/106] REX changes - larryk85's PR review --- contracts/eosio.system/src/rex.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index d47017f40..380cd8cc9 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -622,23 +622,24 @@ namespace eosiosystem { void system_contract::update_rex_pool() { const time_point ct = current_time_point(); + const auto ret_pool_elem = _rexretpool.begin(); - if ( _rexretpool.begin() == _rexretpool.end() || - ct < _rexretpool.begin()->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { + if ( ret_pool_elem == _rexretpool.end() || + ct < ret_pool_elem->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { return; } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint64_t time_interval = ct.time_since_epoch().count() - _rexretpool.begin()->last_update_time.time_since_epoch().count(); + const int64_t current_rate = ret_pool_elem->current_rate_of_increase; + const uint64_t time_interval = ct.time_since_epoch().count() - ret_pool_elem->last_update_time.time_since_epoch().count(); const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; - const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() - && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first - && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; + const bool new_return_bucket = !ret_pool_elem->return_buckets.empty() + && ret_pool_elem->last_update_time <= ret_pool_elem->return_buckets.rbegin()->first + && ret_pool_elem->return_buckets.rbegin()->first <= ct; int64_t new_bucket_estimate = 0; if ( new_return_bucket ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; @@ -647,7 +648,7 @@ namespace eosiosystem { int64_t change = change_estimate + new_bucket_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); while ( iter != return_buckets.end() && iter->first <= time_threshold ) { @@ -673,7 +674,7 @@ namespace eosiosystem { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { rp.cummulative_proceeds += change; }); } From 798a32938cc1e7011920551e8cdbaa7aa25ae371 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 10 Dec 2019 18:02:50 -0500 Subject: [PATCH 096/106] REX changes - arhag's PR review --- .../include/eosio.system/eosio.system.hpp | 67 ++++---- contracts/eosio.system/src/eosio.system.cpp | 1 + contracts/eosio.system/src/rex.cpp | 147 +++++++++++------- 3 files changed, 130 insertions(+), 85 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 95108dc9c..4b24caff1 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -341,25 +341,33 @@ namespace eosiosystem { // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, - // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective + // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { - uint8_t version = 0; - - time_point last_update_time; - int64_t current_rate_of_increase = 0; - int64_t cummulative_proceeds = 0; - int64_t proceeds = 0; - std::map return_buckets; - - static constexpr int64_t total_duration = 30 * useconds_per_day; - static constexpr int64_t dist_interval = 10 * 60 * 1000'000; - static constexpr uint8_t hours_per_bucket = 12; + uint8_t version = 0; + time_point_sec last_dist_time; + time_point_sec pending_bucket_time = time_point_sec::maximum(); + time_point_sec oldest_bucket_time = time_point_sec::min(); + int64_t pending_bucket_proceeds = 0; + int64_t current_rate_of_increase = 0; + + static constexpr int32_t total_intervals = 30 * 144; // 30 days + static constexpr int32_t dist_interval = 10 * 60; // 10 minutes + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_buckets { + uint8_t version = 0; + std::map return_buckets; + + uint64_t primary_key()const { return 0; } + }; + + typedef eosio::multi_index< "retbuckets"_n, rex_return_buckets > rex_return_buckets_table; + // `rex_fund` structure underlying the rex fund table. A rex fund table entry is defined by: // - `version` defaulted to zero, // - `owner` the owner of the rex fund, @@ -457,23 +465,24 @@ namespace eosiosystem { class [[eosio::contract("eosio.system")]] system_contract : public native { private: - voters_table _voters; - producers_table _producers; - producers_table2 _producers2; - global_state_singleton _global; - global_state2_singleton _global2; - global_state3_singleton _global3; - global_state4_singleton _global4; - eosio_global_state _gstate; - eosio_global_state2 _gstate2; - eosio_global_state3 _gstate3; - eosio_global_state4 _gstate4; - rammarket _rammarket; - rex_pool_table _rexpool; - rex_return_pool_table _rexretpool; - rex_fund_table _rexfunds; - rex_balance_table _rexbalance; - rex_order_table _rexorders; + voters_table _voters; + producers_table _producers; + producers_table2 _producers2; + global_state_singleton _global; + global_state2_singleton _global2; + global_state3_singleton _global3; + global_state4_singleton _global4; + eosio_global_state _gstate; + eosio_global_state2 _gstate2; + eosio_global_state3 _gstate3; + eosio_global_state4 _gstate4; + rammarket _rammarket; + rex_pool_table _rexpool; + rex_return_pool_table _rexretpool; + rex_return_buckets_table _rexretbuckets; + rex_fund_table _rexfunds; + rex_balance_table _rexbalance; + rex_order_table _rexorders; public: static constexpr eosio::name active_permission{"active"_n}; diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index a6af9e0d0..202210c7d 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -27,6 +27,7 @@ namespace eosiosystem { _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), + _rexretbuckets(get_self(), get_self().value), _rexfunds(get_self(), get_self().value), _rexbalance(get_self(), get_self().value), _rexorders(get_self(), get_self().value) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 380cd8cc9..663336d2f 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -621,62 +621,92 @@ namespace eosiosystem { */ void system_contract::update_rex_pool() { - const time_point ct = current_time_point(); - const auto ret_pool_elem = _rexretpool.begin(); + auto get_elapsed_intervals = [&](const time_point_sec& t1, const time_point_sec& t0) -> uint32_t { + return (t1.sec_since_epoch() - t0.sec_since_epoch()) / rex_return_pool::dist_interval; + }; + + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const time_point_sec effective_time{cts - cts % rex_return_pool::dist_interval}; - if ( ret_pool_elem == _rexretpool.end() || - ct < ret_pool_elem->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { + const auto ret_pool_elem = _rexretpool.begin(); + const auto ret_buckets_elem = _rexretbuckets.begin(); + + if ( ret_pool_elem == _rexretpool.end() || effective_time <= ret_pool_elem->last_dist_time ) { return; } - const int64_t current_rate = ret_pool_elem->current_rate_of_increase; - const uint64_t time_interval = ct.time_since_epoch().count() - ret_pool_elem->last_update_time.time_since_epoch().count(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; - const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; + const int64_t current_rate = ret_pool_elem->current_rate_of_increase; + const uint32_t elapsed_intervals = get_elapsed_intervals(effective_time, ret_pool_elem->last_dist_time); + int64_t change_estimate = current_rate * elapsed_intervals; - const bool new_return_bucket = !ret_pool_elem->return_buckets.empty() - && ret_pool_elem->last_update_time <= ret_pool_elem->return_buckets.rbegin()->first - && ret_pool_elem->return_buckets.rbegin()->first <= ct; - int64_t new_bucket_estimate = 0; - if ( new_return_bucket ) { + { + const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; + int64_t new_bucket_rate = 0; + time_point_sec new_bucket_time{0}; _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; - new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; + if ( new_return_bucket ) { + int64_t remainder = rp.pending_bucket_proceeds % rex_return_pool::total_intervals; + new_bucket_rate = ( rp.pending_bucket_proceeds - remainder ) / rex_return_pool::total_intervals; + new_bucket_time = rp.pending_bucket_time; + rp.current_rate_of_increase += new_bucket_rate; + change_estimate += remainder + new_bucket_rate * get_elapsed_intervals( effective_time, rp.pending_bucket_time ); + rp.pending_bucket_proceeds = 0; + rp.pending_bucket_time = time_point_sec::maximum(); + if ( new_bucket_time < rp.oldest_bucket_time ) { + rp.oldest_bucket_time = new_bucket_time; + } + } + rp.last_dist_time = effective_time; }); + + if ( new_return_bucket ) { + _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { + rb.return_buckets[new_bucket_time] = new_bucket_rate; + }); + } } - int64_t change = change_estimate + new_bucket_estimate; + const time_point_sec time_threshold = effective_time - eosio::seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); + if ( ret_pool_elem->oldest_bucket_time <= time_threshold ) { + int64_t expired_rate = 0; + int64_t surplus = 0; + _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { + auto& return_buckets = rb.return_buckets; + auto iter = return_buckets.begin(); + while ( iter != return_buckets.end() && iter->first <= time_threshold ) { + auto next = iter; + ++next; + const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + rex_return_pool::total_intervals ); + surplus += iter->second * overtime; + expired_rate += iter->second; + return_buckets.erase(iter); + } + }); - _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - auto& return_buckets = rp.return_buckets; - auto iter = return_buckets.begin(); - while ( iter != return_buckets.end() && iter->first <= time_threshold ) { - auto next = iter; - ++next; - const uint64_t overtime = ct.time_since_epoch().count() - ( iter->first.time_since_epoch().count() + rex_return_pool::total_duration ); - const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) - / rex_return_pool::total_duration; - change -= surplus; - rp.current_rate_of_increase -= rate; - return_buckets.erase(iter); - iter = next; - } - rp.last_update_time = ct; - }); + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { + if ( !ret_buckets_elem->return_buckets.empty() ) { + rp.oldest_bucket_time = ret_buckets_elem->return_buckets.begin()->first; + } else { + rp.oldest_bucket_time = time_point_sec::min(); + } - if ( change <= 0 ) { - return; + if ( expired_rate > 0) { + rp.current_rate_of_increase -= expired_rate; + } + }); + + if ( surplus > 0 ) { + change_estimate -= surplus; + } } - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { - pool.total_unlent.amount += change; - pool.total_lendable = pool.total_unlent + pool.total_lent; - }); - _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - rp.cummulative_proceeds += change; - }); + if ( change_estimate > 0 ) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { + pool.total_unlent.amount += change_estimate; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + } } template @@ -1029,25 +1059,30 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); + if ( fee.amount <= 0) { + return; + } - const int64_t cts = current_time_point().time_since_epoch().count(); - const int64_t bucket_interval = rex_return_pool::hours_per_bucket * useconds_per_hour; - const time_point effective_time{ eosio::microseconds{cts - cts % bucket_interval + bucket_interval} }; - - if ( _rexretpool.begin() == _rexretpool.end() ) { + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; + const time_point_sec effective_time{cts - cts % bucket_interval + bucket_interval}; + const auto return_pool_elem = _rexretpool.begin(); + if ( return_pool_elem == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { - rp.last_update_time = effective_time; - rp.proceeds += fee.amount; + rp.last_dist_time = effective_time; + rp.pending_bucket_proceeds = fee.amount; + rp.pending_bucket_time = effective_time; }); + _rexretbuckets.emplace( get_self(), [&]( auto& rb ) { } ); } else { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { - rp.proceeds += fee.amount; + _rexretpool.modify( return_pool_elem, same_payer, [&]( auto& rp ) { + rp.pending_bucket_proceeds += fee.amount; + if ( rp.pending_bucket_time == time_point_sec::maximum() ) { + rp.pending_bucket_time = effective_time; + } }); } - - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { - rp.return_buckets[effective_time] += fee.amount; - }); } /** From dbf8c45cbc7c196c64e6a03e4dc6ac1a7b3835a6 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 00:47:04 -0500 Subject: [PATCH 097/106] REX changes - tests --- contracts/eosio.system/src/rex.cpp | 18 ++--- tests/eosio.system_tester.hpp | 21 ++++++ tests/eosio.system_tests.cpp | 105 +++++++++++++++++------------ 3 files changed, 94 insertions(+), 50 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 663336d2f..c775a25b7 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -6,6 +6,7 @@ namespace eosiosystem { using eosio::current_time_point; using eosio::token; + using eosio::seconds; void system_contract::deposit( const name& owner, const asset& amount ) { @@ -621,8 +622,8 @@ namespace eosiosystem { */ void system_contract::update_rex_pool() { - auto get_elapsed_intervals = [&](const time_point_sec& t1, const time_point_sec& t0) -> uint32_t { - return (t1.sec_since_epoch() - t0.sec_since_epoch()) / rex_return_pool::dist_interval; + auto get_elapsed_intervals = [&]( const time_point_sec& t1, const time_point_sec& t0 ) -> uint32_t { + return ( t1.sec_since_epoch() - t0.sec_since_epoch() ) / rex_return_pool::dist_interval; }; const time_point_sec ct = current_time_point(); @@ -637,13 +638,13 @@ namespace eosiosystem { } const int64_t current_rate = ret_pool_elem->current_rate_of_increase; - const uint32_t elapsed_intervals = get_elapsed_intervals(effective_time, ret_pool_elem->last_dist_time); + const uint32_t elapsed_intervals = get_elapsed_intervals( effective_time, ret_pool_elem->last_dist_time ); int64_t change_estimate = current_rate * elapsed_intervals; { const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; int64_t new_bucket_rate = 0; - time_point_sec new_bucket_time{0}; + time_point_sec new_bucket_time = time_point_sec::min(); _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { if ( new_return_bucket ) { int64_t remainder = rp.pending_bucket_proceeds % rex_return_pool::total_intervals; @@ -667,7 +668,7 @@ namespace eosiosystem { } } - const time_point_sec time_threshold = effective_time - eosio::seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); + const time_point_sec time_threshold = effective_time - seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); if ( ret_pool_elem->oldest_bucket_time <= time_threshold ) { int64_t expired_rate = 0; int64_t surplus = 0; @@ -677,10 +678,12 @@ namespace eosiosystem { while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + rex_return_pool::total_intervals ); + const uint32_t overtime = get_elapsed_intervals( effective_time, + iter->first + seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval) ); surplus += iter->second * overtime; expired_rate += iter->second; return_buckets.erase(iter); + iter = next; } }); @@ -690,7 +693,6 @@ namespace eosiosystem { } else { rp.oldest_bucket_time = time_point_sec::min(); } - if ( expired_rate > 0) { rp.current_rate_of_increase -= expired_rate; } @@ -1059,7 +1061,7 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - if ( fee.amount <= 0) { + if ( fee.amount <= 0 ) { return; } diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index acf3b6c60..809361e8e 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -659,6 +659,27 @@ class eosio_system_tester : public TESTER { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_pool", data, abi_serializer_max_time ); } + fc::variant get_rex_return_buckets() const { + vector data; + const auto& db = control->db(); + namespace chain = eosio::chain; + const auto* t_id = db.find( boost::make_tuple( config::system_account_name, config::system_account_name, N(retbuckets) ) ); + if ( !t_id ) { + return fc::variant(); + } + + const auto& idx = db.get_index(); + + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, 0 ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || 0 != itr->primary_key ) { + return fc::variant(); + } + + data.resize( itr->value.size() ); + memcpy( data.data(), itr->value.data(), data.size() ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_buckets", data, abi_serializer_max_time ); + } + void setup_rex_accounts( const std::vector& accounts, const asset& init_balance, const asset& net = core_sym::from_string("80.0000"), diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 63e0f5f91..bea3be00d 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3889,7 +3889,8 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + int64_t rate = fee.get_amount() / (30 * 144); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob @@ -3897,8 +3898,7 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); auto expected_rex_fund = (init_balance + fee).get_amount(); auto actual_rex_fund = get_rex_fund(alice).get_amount(); - BOOST_REQUIRE_EQUAL( true, within_error( expected_rex_fund, actual_rex_fund, 2 ) ); - BOOST_TEST_REQUIRE( actual_rex_fund <= expected_rex_fund ); + BOOST_REQUIRE_EQUAL( expected_rex_fund, actual_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -4368,10 +4368,9 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); - - BOOST_TEST_REQUIRE( within_error( cur_rex_balance.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 4 ) ); - BOOST_TEST_REQUIRE( cur_rex_balance.get_amount() >= get_rex_pool()["total_lendable"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), get_rex_pool()["total_unlent"].as() ); + BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), + get_rex_pool()["total_unlent"].as() ); } FC_LOG_AND_RETHROW() @@ -4804,8 +4803,8 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_rex.get_amount()) * total_lendable ) / total_rex; const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); - BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_TEST_REQUIRE( within_error( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount(), 2 ) ); + BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance(alice) + rex_sell_amount ); + BOOST_REQUIRE_EQUAL( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake(alice).get_amount() ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4884,14 +4883,14 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 2 ) ); + BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 3 ) ); + BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + get_rex_vote_stake(alice) ) == get_producer_info(producer_names[0])["total_votes"].as_double() ); @@ -5160,6 +5159,8 @@ BOOST_FIXTURE_TEST_CASE( b1_vesting, eosio_system_tester ) try { BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { + constexpr uint32_t total_intervals = 30 * 144; + constexpr uint32_t dist_interval = 10 * 60; BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); const asset init_balance = core_sym::from_string("100000.0000"); @@ -5183,16 +5184,17 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); - int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + int64_t rate = fee.get_amount() / total_intervals; + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); - int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); + int32_t t1 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + int64_t change = rate * ((t1-t0) / dist_interval) + fee.get_amount() % total_intervals; int64_t expected = payment.get_amount() + change; auto rex_pool = get_rex_pool(); @@ -5202,13 +5204,14 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { produce_block( fc::days(25) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - int64_t t2 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int64_t t2 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + change = rate * ((t2-t0) / dist_interval) + fee.get_amount() % total_intervals; expected = payment.get_amount() + change; rex_pool = get_rex_pool(); - BOOST_TEST_REQUIRE( within_one( expected, rex_pool["total_lendable"].as().get_amount() ) ); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); produce_blocks( 1 ); produce_block( fc::days(5) ); @@ -5216,12 +5219,11 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); rex_pool = get_rex_pool(); expected = payment.get_amount() + fee.get_amount(); - BOOST_TEST_REQUIRE( within_error( expected, rex_pool["total_lendable"].as().get_amount(), 2 ) ); - BOOST_TEST_REQUIRE( expected >= rex_pool["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); BOOST_REQUIRE_EQUAL( rex_pool["total_lendable"].as(), rex_pool["total_unlent"].as() ); } @@ -5233,38 +5235,39 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { const asset fee = core_sym::from_string("15.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); - int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + uint32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); produce_block( fc::hours(1) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); - int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + uint32_t t1 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( t1, t0 + 6 * dist_interval ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( 2, rex_return_pool["return_buckets"].get_array().size() ); - BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int64_t rate = 2 * fee.get_amount() / total_intervals; + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::hours(8) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(30) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( fee.get_amount() / total_intervals, rex_return_pool["current_rate_of_increase"].as() ); BOOST_TEST_REQUIRE( (init_lendable + fee + fee).get_amount() < get_rex_pool()["total_lendable"].as().get_amount() ); produce_block( fc::days(1) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); - BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), - get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( init_lendable.get_amount() + 3 * fee.get_amount(), + get_rex_pool()["total_lendable"].as().get_amount() ); } { @@ -5274,24 +5277,42 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_0 = get_rex_pool(); auto rex_return_pool_0 = get_rex_return_pool(); - produce_block( fc::minutes(9) ); + produce_block( fc::minutes(2) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_1 = get_rex_pool(); auto rex_return_pool_1 = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_update_time"].as().time_since_epoch().count(), - rex_return_pool_1["last_update_time"].as().time_since_epoch().count()); + BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_dist_time"].as().sec_since_epoch(), + rex_return_pool_1["last_dist_time"].as().sec_since_epoch() ); BOOST_REQUIRE_EQUAL( rex_pool_0["total_lendable"].as(), - rex_pool_1["total_lendable"].as()); - produce_block( fc::minutes(1) ); + rex_pool_1["total_lendable"].as() ); + produce_block( fc::minutes(9) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_2 = get_rex_pool(); auto rex_return_pool_2 = get_rex_return_pool(); - BOOST_TEST_REQUIRE( rex_return_pool_1["last_update_time"].as().time_since_epoch().count() < - rex_return_pool_2["last_update_time"].as().time_since_epoch().count()); + BOOST_TEST_REQUIRE( rex_return_pool_1["last_dist_time"].as().sec_since_epoch() < + rex_return_pool_2["last_dist_time"].as().sec_since_epoch() ); BOOST_TEST_REQUIRE( rex_pool_1["total_lendable"].as().get_amount() < - rex_pool_2["total_lendable"].as().get_amount()); + rex_pool_2["total_lendable"].as().get_amount() ); + produce_block( fc::days(31) ); + produce_blocks( 1 ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_pool()["current_rate_of_increase"].as() ); } + { + const asset fee = core_sym::from_string("30.0000"); + for ( uint8_t i = 0; i < 5; ++i ) { + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + produce_block( fc::days(1) ); + } + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 5, get_rex_return_buckets()["return_buckets"].get_array().size() ); + produce_block( fc::days(30) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + } + } FC_LOG_AND_RETHROW() From 77c5b9a2ccda1c82ade011fb82b076a0d79c5a0c Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 11:16:53 -0500 Subject: [PATCH 098/106] REX changes - updated comments --- .../include/eosio.system/eosio.system.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4b24caff1..57f1d529e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -337,11 +337,11 @@ namespace eosiosystem { // `rex_return_pool` structure underlying the rex return pool table. A rex return pool table entry is defined by: // - `version` defaulted to zero, - // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, - // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, - // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, - // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, - // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective + // - `last_dist_time` the last time proceeds from renting, ram fees, and name bids were added to the rex pool, + // - `pending_bucket_time` timestamp of the pending 12-hour return bucket, + // - `oldest_bucket_time` cached timestamp of the oldest 12-hour return bucket, + // - `pending_bucket_proceeds` proceeds in the pending 12-hour return bucket, + // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point_sec last_dist_time; @@ -350,15 +350,18 @@ namespace eosiosystem { int64_t pending_bucket_proceeds = 0; int64_t current_rate_of_increase = 0; - static constexpr int32_t total_intervals = 30 * 144; // 30 days - static constexpr int32_t dist_interval = 10 * 60; // 10 minutes - static constexpr uint8_t hours_per_bucket = 12; + static constexpr uint32_t total_intervals = 30 * 144; // 30 days + static constexpr uint32_t dist_interval = 10 * 60; // 10 minutes + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + // `rex_return_buckets` structure underlying the rex return buckets table. A rex return buckets table is defined by: + // - `version` defaulted to zero, + // - `return_buckets` buckets of proceeds accumulated in 12-hour intervals struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_buckets { uint8_t version = 0; std::map return_buckets; From d53d2d8f9d5f8441b7710e9ae63f2d2f34738d7e Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 15:20:49 -0500 Subject: [PATCH 099/106] REX changes - additional checks --- .../include/eosio.system/eosio.system.hpp | 5 ++++- contracts/eosio.system/src/rex.cpp | 20 ++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 57f1d529e..3cfce3f42 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -341,7 +341,8 @@ namespace eosiosystem { // - `pending_bucket_time` timestamp of the pending 12-hour return bucket, // - `oldest_bucket_time` cached timestamp of the oldest 12-hour return bucket, // - `pending_bucket_proceeds` proceeds in the pending 12-hour return bucket, - // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool + // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool, + // - `proceeds` the maximum amount of proceeds that can be added to the rex pool at any given time struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point_sec last_dist_time; @@ -349,10 +350,12 @@ namespace eosiosystem { time_point_sec oldest_bucket_time = time_point_sec::min(); int64_t pending_bucket_proceeds = 0; int64_t current_rate_of_increase = 0; + int64_t proceeds = 0; static constexpr uint32_t total_intervals = 30 * 144; // 30 days static constexpr uint32_t dist_interval = 10 * 60; // 10 minutes static constexpr uint8_t hours_per_bucket = 12; + static_assert( total_intervals * dist_interval == 30 * seconds_per_day ); uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index c775a25b7..8e9d881f3 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -642,7 +642,7 @@ namespace eosiosystem { int64_t change_estimate = current_rate * elapsed_intervals; { - const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; + const bool new_return_bucket = ret_pool_elem->pending_bucket_time <= effective_time; int64_t new_bucket_rate = 0; time_point_sec new_bucket_time = time_point_sec::min(); _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { @@ -658,6 +658,7 @@ namespace eosiosystem { rp.oldest_bucket_time = new_bucket_time; } } + rp.proceeds -= change_estimate; rp.last_dist_time = effective_time; }); @@ -696,11 +697,18 @@ namespace eosiosystem { if ( expired_rate > 0) { rp.current_rate_of_increase -= expired_rate; } + if ( surplus > 0 ) { + change_estimate -= surplus; + rp.proceeds += surplus; + } }); + } - if ( surplus > 0 ) { - change_estimate -= surplus; - } + if ( change_estimate > 0 && ret_pool_elem->proceeds < 0 ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { + change_estimate += rp.proceeds; + rp.proceeds = 0; + }); } if ( change_estimate > 0 ) { @@ -1074,12 +1082,14 @@ namespace eosiosystem { _rexretpool.emplace( get_self(), [&]( auto& rp ) { rp.last_dist_time = effective_time; rp.pending_bucket_proceeds = fee.amount; - rp.pending_bucket_time = effective_time; + rp.pending_bucket_time = effective_time; + rp.proceeds = fee.amount; }); _rexretbuckets.emplace( get_self(), [&]( auto& rb ) { } ); } else { _rexretpool.modify( return_pool_elem, same_payer, [&]( auto& rp ) { rp.pending_bucket_proceeds += fee.amount; + rp.proceeds += fee.amount; if ( rp.pending_bucket_time == time_point_sec::maximum() ) { rp.pending_bucket_time = effective_time; } From 05f75e97c5658a1de4c4df323a76134d7ed6117f Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 18:59:46 -0500 Subject: [PATCH 100/106] REX changes - fix build issues --- tests/eosio.system_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index bea3be00d..a1ba21bda 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4776,9 +4776,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, { producer_names.begin(), producer_names.begin() + 20 } ) ); + vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 20 ) ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4812,7 +4812,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names[0], producer_names[4] } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names[0], producer_names[4] ) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); @@ -4868,7 +4868,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == From 5a5854e47d73e59be49266494b5423a64ebed096 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:08:50 -0500 Subject: [PATCH 101/106] REX changes - fix build issues --- tests/eosio.system_tests.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index a1ba21bda..10581701c 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4776,9 +4776,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 20 ) ) ); + vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 20) ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); + vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4812,7 +4812,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names[0], producer_names[4] ) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); @@ -4854,7 +4854,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_REQUIRE_EQUAL( purchase, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( purchase.get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); @@ -4868,7 +4868,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == From 23b6938153253fb335303d1d55801059de68be31 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:38:54 -0500 Subject: [PATCH 102/106] REX changes - tests --- tests/eosio.system_tests.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 10581701c..09d481927 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4033,9 +4033,6 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol{SY(4,REX)} ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); - // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); - // BOOST_REQUIRE_EQUAL( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ); - // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); @@ -4786,7 +4783,11 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); + + produce_blocks( 1 ); produce_block( fc::days(10) ); + produce_blocks( 1 ); + BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); @@ -4794,7 +4795,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); + produce_blocks( 1 ); produce_block( fc::hours(19 * 24 + 23) ); + produce_blocks( 1 ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); @@ -4808,8 +4812,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); - + + produce_blocks( 1 ); produce_block( fc::days(31) ); + produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); From 46a5bd707ed3325ea61ddb8f61c6f0bc90686b7e Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:47:03 -0500 Subject: [PATCH 103/106] REX changes - tests --- tests/eosio.system_tests.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 09d481927..9c9746089 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4818,7 +4818,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); + std::vector two_producers; + two_producers.push_back( producer_names[0] ); + two_producers.push_back( producer_names[4] ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, two_producers ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); From a1b28f03efa3466b28e239325cf0f52e286bdcf3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Thu, 12 Dec 2019 10:34:37 -0500 Subject: [PATCH 104/106] REX changes - code cleaning --- tests/eosio.system_tests.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 9c9746089..eca4dcd56 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4783,11 +4783,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - - produce_blocks( 1 ); produce_block( fc::days(10) ); - produce_blocks( 1 ); - BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); @@ -4795,10 +4791,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); - produce_blocks( 1 ); produce_block( fc::hours(19 * 24 + 23) ); - produce_blocks( 1 ); - BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); @@ -4812,16 +4805,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); - - produce_blocks( 1 ); produce_block( fc::days(31) ); - produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - std::vector two_producers; - two_producers.push_back( producer_names[0] ); - two_producers.push_back( producer_names[4] ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, two_producers ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names[0], producer_names[4] } ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); From 2f5e46c99e4f2c5a6feaf35b4c177072a6c84e81 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 13 Dec 2019 14:41:28 -0500 Subject: [PATCH 105/106] REX changes - arhag's PR review --- tests/eosio.system_tests.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index eca4dcd56..7021e927b 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5175,13 +5175,18 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { } { - const asset fee = core_sym::from_string("30.0000"); + const asset fee = core_sym::from_string("30.0000"); + const uint32_t bucket_interval_sec = fc::hours(12).to_seconds(); + const uint32_t current_time_sec = control->pending_block_time().sec_since_epoch(); + const time_point_sec expected_pending_bucket_time{current_time_sec - current_time_sec % bucket_interval_sec + bucket_interval_sec}; BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); - int32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( expected_pending_bucket_time.sec_since_epoch(), + rex_return_pool["pending_bucket_time"].as().sec_since_epoch() ); + int32_t t0 = rex_return_pool["pending_bucket_time"].as().sec_since_epoch(); produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); From 9f491b969c28b9a0c72583bf100e83f976bc0b66 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 10:24:15 -0500 Subject: [PATCH 106/106] bump version to v1.8.3 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e21c73d0c..5783e8319 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 8) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) #set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index b98bf5db5..34fb56efd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.8.2 +## Version : 1.8.3 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 bios, system, msig, wrap (formerly known as sudo) and token contracts.