From 9a5df11867019a75933efac63d10e55aac0ec2b5 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 27 Nov 2019 11:24:28 -0500 Subject: [PATCH 01/78] resource31 --- contracts/eosio.system/CMakeLists.txt | 1 + .../include/eosio.system/eosio.system.hpp | 99 +++++++++++++++++++ contracts/eosio.system/src/resource31.cpp | 31 ++++++ tests/eosio.resource31_tests.cpp | 24 +++++ 4 files changed, 155 insertions(+) create mode 100644 contracts/eosio.system/src/resource31.cpp create mode 100644 tests/eosio.resource31_tests.cpp diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index 3f9090846..d8d62b1d2 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -4,6 +4,7 @@ add_contract(eosio.system eosio.system ${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/resource31.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp ) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index fb7e8cdb1..753e235ce 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -87,6 +87,7 @@ 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 resource market separate from REX: `buycpu31`, `buynet31` */ // A name bid, which consists of: @@ -469,6 +470,46 @@ namespace eosiosystem { asset stake_change; }; + enum resource31_type: uint8_t { + cpu = 0, + net = 1, + }; + + struct [[eosio::table,eosio::contract("eosio.system")]] resource31_state { + uint8_t version = 0; + uint8_t type; // resource31_type + int64_t weight; + int64_t initial_weight; + int64_t target_weight; + time_point_sec initial_timestamp; + time_point_sec target_timestamp; + time_point_sec last_update; + double exponent; + uint32_t window; + asset peak_price; + asset min_purchase_price; + int64_t sold; + + uint64_t primary_key()const { return type; } + }; + + typedef eosio::multi_index<"res31.state"_n, resource31_state> resource31_state_table; + + struct [[eosio::table,eosio::contract("eosio.system")]] resource31_order { + uint8_t version = 0; + uint64_t id; + name owner; + uint8_t type; // resource31_type + int64_t weight; + time_point_sec expires; + + uint64_t primary_key()const { return id; } + uint64_t by_owner()const { return owner.value; } + }; + + typedef eosio::multi_index< "res31.order"_n, resource31_order, + indexed_by<"byowner"_n, const_mem_fun>> resource31_order_table; + /** * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. */ @@ -1122,6 +1163,60 @@ namespace eosiosystem { [[eosio::action]] void setinflation( int64_t annual_rate, int64_t inflation_pay_factor, int64_t votepay_factor ); + /** + * Configure or modify the `buycpu31` market. The market becomes available the first time this + * action is invoked. + * + * @param delta_weight - immediately adjust the market cap by this amount. 1 represents the same amount of + * resources as 1 satoshi of SYS staked. + * @param target_weight - linearly grow the market cap to this amount. + * @param target_timestamp - stop automatic market growth at this time. Once this time hits, the market + * cap will be `target_weight`. + */ + [[eosio::action]] + void configcpu31( int64_t delta_weight, int64_t target_weight, const time_point_sec& target_timestamp, + double exponent, uint32_t window, const asset& peak_price, const asset& min_purchase_price ); + + /** + * Configure or modify the `buynet31` market. The market becomes available the first time this + * action is invoked. + * + * @param delta_weight - immediately adjust the market cap by this amount. 1 represents the same amount of + * resources as 1 satoshi of SYS staked. + * @param target_weight - linearly grow the market cap to this amount. + * @param target_timestamp - stop automatic market growth at this time. Once this time hits, the market + * cap will be `target_weight`. + */ + [[eosio::action]] + void confignet31( int64_t delta_weight, int64_t target_weight, const time_point_sec& target_timestamp, + double exponent, uint32_t window, const asset& peak_price, const asset& min_purchase_price ); + + /** + * Buy CPU for 31 days. + * + * @param payer - the resource buyer + * @param receiver - the resource receiver + * @param amount - the amount of resource to buy. 1 has the same amount of resources as + * 1 satoshi of SYS staked. + * @param max_payment - the maximum amount `payer` is willing to pay. Tokens are withdrawn from + * `payer`'s token balance. + */ + [[eosio::action]] + void buycpu31( const name& payer, const name& receiver, int64_t amount, const asset& max_payment ); + + /** + * Buy NET for 31 days. + * + * @param payer - the resource buyer + * @param receiver - the resource receiver + * @param amount - the amount of resource to buy. 1 has the same amount of resources as + * 1 satoshi of SYS staked. + * @param max_payment - the maximum amount `payer` is willing to pay. Tokens are withdrawn from + * `payer`'s token balance. + */ + [[eosio::action]] + void buynet31( const name& payer, const name& receiver, int64_t amount, const asset& max_payment ); + using init_action = eosio::action_wrapper<"init"_n, &system_contract::init>; using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; using setacctnet_action = eosio::action_wrapper<"setacctnet"_n, &system_contract::setacctnet>; @@ -1168,6 +1263,10 @@ namespace eosiosystem { using setalimits_action = eosio::action_wrapper<"setalimits"_n, &system_contract::setalimits>; using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; + using configcpu31_action = eosio::action_wrapper<"configcpu31"_n, &system_contract::configcpu31>; + using confignet31_action = eosio::action_wrapper<"confignet31"_n, &system_contract::confignet31>; + using buycpu31_action = eosio::action_wrapper<"buycpu31"_n, &system_contract::buycpu31>; + using buynet31_action = eosio::action_wrapper<"buynet31"_n, &system_contract::buynet31>; private: // Implementation details: diff --git a/contracts/eosio.system/src/resource31.cpp b/contracts/eosio.system/src/resource31.cpp new file mode 100644 index 000000000..fc0134a83 --- /dev/null +++ b/contracts/eosio.system/src/resource31.cpp @@ -0,0 +1,31 @@ +#include + +namespace eosiosystem { + +void system_contract::configcpu31(int64_t delta_weight, int64_t target_weight, + const time_point_sec& target_timestamp, + double exponent, uint32_t window, + const asset& peak_price, + const asset& min_purchase_price) { + // +} + +void system_contract::confignet31(int64_t delta_weight, int64_t target_weight, + const time_point_sec& target_timestamp, + double exponent, uint32_t window, + const asset& peak_price, + const asset& min_purchase_price) { + // +} + +void system_contract::buycpu31(const name& payer, const name& receiver, + int64_t amount, const asset& max_payment) { + // +} + +void system_contract::buynet31(const name& payer, const name& receiver, + int64_t amount, const asset& max_payment) { + // +} + +} // namespace eosiosystem diff --git a/tests/eosio.resource31_tests.cpp b/tests/eosio.resource31_tests.cpp new file mode 100644 index 000000000..b25261a7e --- /dev/null +++ b/tests/eosio.resource31_tests.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "eosio.system_tester.hpp" + +using namespace eosio_system; + +BOOST_AUTO_TEST_SUITE(eosio_system_resource31_tests) + +BOOST_FIXTURE_TEST_CASE(foo, eosio_system_tester) try { + // +} +FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() From 6994ec3c7cfb1366145ad410a0f172e2f24e023d Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 27 Nov 2019 16:00:30 -0500 Subject: [PATCH 02/78] buybandwidth --- contracts/eosio.system/CMakeLists.txt | 2 +- .../include/eosio.system/eosio.system.hpp | 121 ++++++++---------- contracts/eosio.system/src/buybandwidth.cpp | 14 ++ contracts/eosio.system/src/resource31.cpp | 31 ----- ...tests.cpp => eosio.buybandwidth_tests.cpp} | 4 +- 5 files changed, 69 insertions(+), 103 deletions(-) create mode 100644 contracts/eosio.system/src/buybandwidth.cpp delete mode 100644 contracts/eosio.system/src/resource31.cpp rename tests/{eosio.resource31_tests.cpp => eosio.buybandwidth_tests.cpp} (90%) diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index d8d62b1d2..825a02d75 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -1,10 +1,10 @@ add_contract(eosio.system eosio.system + ${CMAKE_CURRENT_SOURCE_DIR}/src/buybandwidth.cpp ${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/resource31.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp ) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 753e235ce..44d03d907 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -87,7 +87,7 @@ 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 resource market separate from REX: `buycpu31`, `buynet31` + * - A resource market separate from REX: `buybandwidth` */ // A name bid, which consists of: @@ -470,45 +470,62 @@ namespace eosiosystem { asset stake_change; }; - enum resource31_type: uint8_t { - cpu = 0, - net = 1, + struct buybw_config_resource { + int64_t current_weight; // Immediately set the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. + int64_t target_weight; // Linearly grow the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. + time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. + // Ignored if current_weight == target_weight. + double exponent; // Exponent of resource price curve. Must be >= 1. + uint32_t decay_days; // Number of days for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + asset total_price; // Total price needed to buy the entire resource market weight. + asset min_purchase_price; // Minimum purchase. This needs to be large enough to cover RAM costs. }; - struct [[eosio::table,eosio::contract("eosio.system")]] resource31_state { + struct buybw_config { + buybw_config_resource net; // NET market configuration + buybw_config_resource cpu; // CPU market configuration + uint32_t purchase_days; // `buybandwidth` `days` argument must match this. + }; + + struct buybw_state_resource { + uint8_t version = 0; + int64_t weight; // resource market weight + int64_t initial_weight; // Initial resource market weight used for linear growth + int64_t target_weight; // Linearly grow the resource market weight to this amount + time_point_sec initial_timestamp; // When resource market weight growth started + time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. + double exponent; // Exponent of resource price curve. + uint32_t decay_days; // Number of days for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + asset total_price; // Total price needed to buy the entire resource market weight. + asset min_purchase_price; // Minimum purchase + int64_t utilization; // Instantaneous resource utilization. This is the current amount sold. + int64_t adjusted_utilization; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. + }; + + struct [[eosio::table("buybw.state"),eosio::contract("eosio.system")]] buybw_state { uint8_t version = 0; - uint8_t type; // resource31_type - int64_t weight; - int64_t initial_weight; - int64_t target_weight; - time_point_sec initial_timestamp; - time_point_sec target_timestamp; - time_point_sec last_update; - double exponent; - uint32_t window; - asset peak_price; - asset min_purchase_price; - int64_t sold; - - uint64_t primary_key()const { return type; } + buybw_state_resource net; // NET market state + buybw_state_resource cpu; // CPU market state + + uint64_t primary_key()const { return 0; } }; - typedef eosio::multi_index<"res31.state"_n, resource31_state> resource31_state_table; + typedef eosio::singleton<"buybw.state"_n, buybw_state> buybw_state_singleton; - struct [[eosio::table,eosio::contract("eosio.system")]] resource31_order { + struct [[eosio::table("buybw.order"),eosio::contract("eosio.system")]] buybw_order { uint8_t version = 0; uint64_t id; name owner; - uint8_t type; // resource31_type - int64_t weight; + int64_t net_weight; + int64_t cpu_weight; time_point_sec expires; uint64_t primary_key()const { return id; } uint64_t by_owner()const { return owner.value; } }; - typedef eosio::multi_index< "res31.order"_n, resource31_order, - indexed_by<"byowner"_n, const_mem_fun>> resource31_order_table; + typedef eosio::multi_index< "buybw.order"_n, buybw_order, + indexed_by<"byowner"_n, const_mem_fun>> buybw_order_table; /** * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. @@ -546,6 +563,7 @@ namespace eosiosystem { static constexpr eosio::name names_account{"eosio.names"_n}; static constexpr eosio::name saving_account{"eosio.saving"_n}; static constexpr eosio::name rex_account{"eosio.rex"_n}; + static constexpr eosio::name reserv_account{"eosio.reserv"_n}; static constexpr eosio::name null_account{"eosio.null"_n}; static constexpr symbol ramcore_symbol = symbol(symbol_code("RAMCORE"), 4); static constexpr symbol ram_symbol = symbol(symbol_code("RAM"), 0); @@ -1164,58 +1182,25 @@ namespace eosiosystem { void setinflation( int64_t annual_rate, int64_t inflation_pay_factor, int64_t votepay_factor ); /** - * Configure or modify the `buycpu31` market. The market becomes available the first time this + * Configure the `buybandwidth` market. The market becomes available the first time this * action is invoked. - * - * @param delta_weight - immediately adjust the market cap by this amount. 1 represents the same amount of - * resources as 1 satoshi of SYS staked. - * @param target_weight - linearly grow the market cap to this amount. - * @param target_timestamp - stop automatic market growth at this time. Once this time hits, the market - * cap will be `target_weight`. - */ - [[eosio::action]] - void configcpu31( int64_t delta_weight, int64_t target_weight, const time_point_sec& target_timestamp, - double exponent, uint32_t window, const asset& peak_price, const asset& min_purchase_price ); - - /** - * Configure or modify the `buynet31` market. The market becomes available the first time this - * action is invoked. - * - * @param delta_weight - immediately adjust the market cap by this amount. 1 represents the same amount of - * resources as 1 satoshi of SYS staked. - * @param target_weight - linearly grow the market cap to this amount. - * @param target_timestamp - stop automatic market growth at this time. Once this time hits, the market - * cap will be `target_weight`. - */ - [[eosio::action]] - void confignet31( int64_t delta_weight, int64_t target_weight, const time_point_sec& target_timestamp, - double exponent, uint32_t window, const asset& peak_price, const asset& min_purchase_price ); - - /** - * Buy CPU for 31 days. - * - * @param payer - the resource buyer - * @param receiver - the resource receiver - * @param amount - the amount of resource to buy. 1 has the same amount of resources as - * 1 satoshi of SYS staked. - * @param max_payment - the maximum amount `payer` is willing to pay. Tokens are withdrawn from - * `payer`'s token balance. */ [[eosio::action]] - void buycpu31( const name& payer, const name& receiver, int64_t amount, const asset& max_payment ); + void configbuybw(const buybw_config& args); /** - * Buy NET for 31 days. + * Buy NET and CPU * * @param payer - the resource buyer * @param receiver - the resource receiver - * @param amount - the amount of resource to buy. 1 has the same amount of resources as - * 1 satoshi of SYS staked. + * @param days - number of days of resource availability. Must match market configuration. + * @param net - fraction of net (100% = 10^18) managed by this market + * @param cpu - fraction of cpu (100% = 10^18) managed by this market * @param max_payment - the maximum amount `payer` is willing to pay. Tokens are withdrawn from * `payer`'s token balance. */ [[eosio::action]] - void buynet31( const name& payer, const name& receiver, int64_t amount, const asset& max_payment ); + void buybandwidth( const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, const asset& max_payment ); using init_action = eosio::action_wrapper<"init"_n, &system_contract::init>; using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; @@ -1263,10 +1248,8 @@ namespace eosiosystem { using setalimits_action = eosio::action_wrapper<"setalimits"_n, &system_contract::setalimits>; using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; - using configcpu31_action = eosio::action_wrapper<"configcpu31"_n, &system_contract::configcpu31>; - using confignet31_action = eosio::action_wrapper<"confignet31"_n, &system_contract::confignet31>; - using buycpu31_action = eosio::action_wrapper<"buycpu31"_n, &system_contract::buycpu31>; - using buynet31_action = eosio::action_wrapper<"buynet31"_n, &system_contract::buynet31>; + using configcpu_action = eosio::action_wrapper<"configbuybw"_n, &system_contract::configbuybw>; + using buybandwidth_action = eosio::action_wrapper<"buybandwidth"_n, &system_contract::buybandwidth>; private: // Implementation details: diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/buybandwidth.cpp new file mode 100644 index 000000000..c25e5b7df --- /dev/null +++ b/contracts/eosio.system/src/buybandwidth.cpp @@ -0,0 +1,14 @@ +#include + +namespace eosiosystem { + +void system_contract::configbuybw(const buybw_config& args) { + // +} + +void system_contract::buybandwidth(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, + const asset& max_payment) { + // +} + +} // namespace eosiosystem diff --git a/contracts/eosio.system/src/resource31.cpp b/contracts/eosio.system/src/resource31.cpp deleted file mode 100644 index fc0134a83..000000000 --- a/contracts/eosio.system/src/resource31.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -namespace eosiosystem { - -void system_contract::configcpu31(int64_t delta_weight, int64_t target_weight, - const time_point_sec& target_timestamp, - double exponent, uint32_t window, - const asset& peak_price, - const asset& min_purchase_price) { - // -} - -void system_contract::confignet31(int64_t delta_weight, int64_t target_weight, - const time_point_sec& target_timestamp, - double exponent, uint32_t window, - const asset& peak_price, - const asset& min_purchase_price) { - // -} - -void system_contract::buycpu31(const name& payer, const name& receiver, - int64_t amount, const asset& max_payment) { - // -} - -void system_contract::buynet31(const name& payer, const name& receiver, - int64_t amount, const asset& max_payment) { - // -} - -} // namespace eosiosystem diff --git a/tests/eosio.resource31_tests.cpp b/tests/eosio.buybandwidth_tests.cpp similarity index 90% rename from tests/eosio.resource31_tests.cpp rename to tests/eosio.buybandwidth_tests.cpp index b25261a7e..41ecadcb9 100644 --- a/tests/eosio.resource31_tests.cpp +++ b/tests/eosio.buybandwidth_tests.cpp @@ -14,10 +14,10 @@ using namespace eosio_system; -BOOST_AUTO_TEST_SUITE(eosio_system_resource31_tests) +BOOST_AUTO_TEST_SUITE(eosio_system_buybandwidth_tests) BOOST_FIXTURE_TEST_CASE(foo, eosio_system_tester) try { - // + // } FC_LOG_AND_RETHROW() From 334ab305ca97f7f19aec82954532c0ee42a52f11 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 27 Nov 2019 17:33:02 -0500 Subject: [PATCH 03/78] buybandwidth --- .../include/eosio.system/eosio.system.hpp | 35 ++++++++--------- contracts/eosio.system/src/buybandwidth.cpp | 38 ++++++++++++++++++- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 44d03d907..539f5908f 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -476,7 +476,7 @@ namespace eosiosystem { time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. // Ignored if current_weight == target_weight. double exponent; // Exponent of resource price curve. Must be >= 1. - uint32_t decay_days; // Number of days for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). asset total_price; // Total price needed to buy the entire resource market weight. asset min_purchase_price; // Minimum purchase. This needs to be large enough to cover RAM costs. }; @@ -488,24 +488,25 @@ namespace eosiosystem { }; struct buybw_state_resource { - uint8_t version = 0; - int64_t weight; // resource market weight - int64_t initial_weight; // Initial resource market weight used for linear growth - int64_t target_weight; // Linearly grow the resource market weight to this amount - time_point_sec initial_timestamp; // When resource market weight growth started - time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. - double exponent; // Exponent of resource price curve. - uint32_t decay_days; // Number of days for adjusted resource utilization to decay to instantaneous utilization within exp(-1). - asset total_price; // Total price needed to buy the entire resource market weight. - asset min_purchase_price; // Minimum purchase - int64_t utilization; // Instantaneous resource utilization. This is the current amount sold. - int64_t adjusted_utilization; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. + uint8_t version = 0; + int64_t weight = 0; // resource market weight + int64_t initial_weight = 0; // Initial resource market weight used for linear growth + int64_t target_weight = 0; // Linearly grow the resource market weight to this amount + time_point_sec initial_timestamp = {}; // When resource market weight growth started + time_point_sec target_timestamp = {}; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. + double exponent = 0; // Exponent of resource price curve. + uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + asset total_price = {}; // Total price needed to buy the entire resource market weight. + asset min_purchase_price = {}; // Minimum purchase + int64_t utilization = 0; // Instantaneous resource utilization. This is the current amount sold. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. }; struct [[eosio::table("buybw.state"),eosio::contract("eosio.system")]] buybw_state { - uint8_t version = 0; - buybw_state_resource net; // NET market state - buybw_state_resource cpu; // CPU market state + uint8_t version = 0; + buybw_state_resource net = {}; // NET market state + buybw_state_resource cpu = {}; // CPU market state + uint32_t purchase_days = 0; // `buybandwidth` `days` argument must match this. uint64_t primary_key()const { return 0; } }; @@ -1186,7 +1187,7 @@ namespace eosiosystem { * action is invoked. */ [[eosio::action]] - void configbuybw(const buybw_config& args); + void configbuybw(buybw_config& args); /** * Buy NET and CPU diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/buybandwidth.cpp index c25e5b7df..f994e482a 100644 --- a/contracts/eosio.system/src/buybandwidth.cpp +++ b/contracts/eosio.system/src/buybandwidth.cpp @@ -2,8 +2,42 @@ namespace eosiosystem { -void system_contract::configbuybw(const buybw_config& args) { - // +void system_contract::configbuybw(buybw_config& args) { + time_point_sec now = eosio::current_time_point(); + auto core_symbol = get_core_symbol(); + buybw_state_singleton state_sing{ get_self(), 0 }; + auto state = state_sing.get_or_default(); + + auto update = [&](auto& state, auto& args) { + if (args.current_weight == args.target_weight) + args.target_timestamp = now; + else + eosio::check(args.target_timestamp > now, "target_timestamp must be in the future"); + eosio::check(args.target_weight >= args.current_weight, "weight can't shrink over time"); + eosio::check(args.current_weight >= state.utilization, "weight can't shrink below utilization"); + eosio::check(args.exponent >= 1, "exponent must be >= 1"); + eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); + eosio::check(args.total_price.symbol == core_symbol, "total_price doesn't match core symbol"); + eosio::check(args.total_price.amount > 0, "total_price must be positive"); + eosio::check(args.min_purchase_price.symbol == core_symbol, "min_purchase_price doesn't match core symbol"); + + state.weight = args.current_weight; + state.initial_weight = args.current_weight; + state.target_weight = args.target_weight; + state.initial_timestamp = now; + state.target_timestamp = args.target_timestamp; + state.exponent = args.exponent; + state.decay_secs = args.decay_secs; + state.total_price = args.total_price; + state.min_purchase_price = args.min_purchase_price; + }; + + eosio::check(args.purchase_days > 0, "purchase_days must be > 0"); + update(state.net, args.net); + update(state.cpu, args.cpu); + state.purchase_days = args.purchase_days; + + state_sing.set(state, get_self()); } void system_contract::buybandwidth(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, From 0a158b5ab85130df61d5fc9c581bc202a1c53faf Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 27 Nov 2019 18:03:34 -0500 Subject: [PATCH 04/78] buybandwidth --- .../include/eosio.system/eosio.system.hpp | 3 + contracts/eosio.system/src/buybandwidth.cpp | 63 ++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 539f5908f..cf7c2ac8f 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1351,6 +1351,9 @@ namespace eosiosystem { }; registration<&system_contract::update_rex_stake> vote_stake_updater{ this }; + + // defined in buybandwidth.cpp + void adjust_resources(name payer, name account, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); }; } diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/buybandwidth.cpp index f994e482a..3126b7d14 100644 --- a/contracts/eosio.system/src/buybandwidth.cpp +++ b/contracts/eosio.system/src/buybandwidth.cpp @@ -2,13 +2,64 @@ namespace eosiosystem { +void system_contract::adjust_resources(name payer, name account, int64_t net_delta, int64_t cpu_delta, + bool must_not_be_managed) { + if (!net_delta && !cpu_delta) + return; + + user_resources_table totals_tbl(get_self(), account.value); + auto tot_itr = totals_tbl.find(account.value); + if (tot_itr == totals_tbl.end()) { + tot_itr = totals_tbl.emplace(payer, [&](auto& tot) { + tot.owner = account; + tot.net_weight = net_delta; + tot.cpu_weight = cpu_delta; + }); + } else { + totals_tbl.modify(tot_itr, same_payer, [&](auto& tot) { + tot.net_weight += net_delta; + tot.cpu_weight += cpu_delta; + }); + } + check(0 <= tot_itr->net_weight.amount, "insufficient staked total net bandwidth"); + check(0 <= tot_itr->cpu_weight.amount, "insufficient staked total cpu bandwidth"); + + { + bool ram_managed = false; + bool net_managed = false; + bool cpu_managed = false; + + auto voter_itr = _voters.find(account.value); + if (voter_itr != _voters.end()) { + ram_managed = has_field(voter_itr->flags1, voter_info::flags1_fields::ram_managed); + net_managed = has_field(voter_itr->flags1, voter_info::flags1_fields::net_managed); + cpu_managed = has_field(voter_itr->flags1, voter_info::flags1_fields::cpu_managed); + } + + if (must_not_be_managed) + eosio::check(!net_managed && !cpu_managed, "something is managed which shouldn't be"); + + if (!(net_managed && cpu_managed)) { + int64_t ram_bytes, net, cpu; + get_resource_limits(account, ram_bytes, net, cpu); + set_resource_limits( + account, 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); + } + } + + if (tot_itr->is_empty()) { + totals_tbl.erase(tot_itr); + } +} // system_contract::adjust_resources + void system_contract::configbuybw(buybw_config& args) { time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); buybw_state_singleton state_sing{ get_self(), 0 }; auto state = state_sing.get_or_default(); - auto update = [&](auto& state, auto& args) { + auto update = [&](auto& state, auto& args, auto& delta_weight) { if (args.current_weight == args.target_weight) args.target_timestamp = now; else @@ -21,6 +72,8 @@ void system_contract::configbuybw(buybw_config& args) { eosio::check(args.total_price.amount > 0, "total_price must be positive"); eosio::check(args.min_purchase_price.symbol == core_symbol, "min_purchase_price doesn't match core symbol"); + delta_weight = args.current_weight - state.weight; + state.weight = args.current_weight; state.initial_weight = args.current_weight; state.target_weight = args.target_weight; @@ -33,10 +86,14 @@ void system_contract::configbuybw(buybw_config& args) { }; eosio::check(args.purchase_days > 0, "purchase_days must be > 0"); - update(state.net, args.net); - update(state.cpu, args.cpu); state.purchase_days = args.purchase_days; + int64_t net_delta = 0; + int64_t cpu_delta = 0; + update(state.net, args.net, net_delta); + update(state.cpu, args.cpu, cpu_delta); + + adjust_resources(get_self(), reserv_account, net_delta, cpu_delta, true); state_sing.set(state, get_self()); } From cd035917b357d4209f2ef17b89d2c0ced1a36a9b Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 27 Nov 2019 18:56:26 -0500 Subject: [PATCH 05/78] buybandwidth --- .../include/eosio.system/eosio.system.hpp | 9 +++- contracts/eosio.system/src/buybandwidth.cpp | 51 +++++++++++++++---- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index cf7c2ac8f..d497311d8 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -523,10 +523,13 @@ namespace eosiosystem { uint64_t primary_key()const { return id; } uint64_t by_owner()const { return owner.value; } + uint64_t by_expires()const { return expires.utc_seconds; } }; typedef eosio::multi_index< "buybw.order"_n, buybw_order, - indexed_by<"byowner"_n, const_mem_fun>> buybw_order_table; + indexed_by<"byowner"_n, const_mem_fun>, + indexed_by<"byexpires"_n, const_mem_fun> + > buybw_order_table; /** * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. @@ -1353,7 +1356,9 @@ namespace eosiosystem { registration<&system_contract::update_rex_stake> vote_stake_updater{ this }; // defined in buybandwidth.cpp - void adjust_resources(name payer, name account, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); + void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); + void process_buybw_queue(symbol core_symbol, buybw_state& state, buybw_order_table& orders, uint32_t max_items); + void update_buybw_state(buybw_state& state); }; } diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/buybandwidth.cpp index 3126b7d14..2f4d1a436 100644 --- a/contracts/eosio.system/src/buybandwidth.cpp +++ b/contracts/eosio.system/src/buybandwidth.cpp @@ -2,8 +2,8 @@ namespace eosiosystem { -void system_contract::adjust_resources(name payer, name account, int64_t net_delta, int64_t cpu_delta, - bool must_not_be_managed) { +void system_contract::adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, + int64_t cpu_delta, bool must_not_be_managed) { if (!net_delta && !cpu_delta) return; @@ -12,13 +12,13 @@ void system_contract::adjust_resources(name payer, name account, int64_t net_del if (tot_itr == totals_tbl.end()) { tot_itr = totals_tbl.emplace(payer, [&](auto& tot) { tot.owner = account; - tot.net_weight = net_delta; - tot.cpu_weight = cpu_delta; + tot.net_weight = asset{ net_delta, core_symbol }; + tot.cpu_weight = asset{ cpu_delta, core_symbol }; }); } else { totals_tbl.modify(tot_itr, same_payer, [&](auto& tot) { - tot.net_weight += net_delta; - tot.cpu_weight += cpu_delta; + tot.net_weight.amount += net_delta; + tot.cpu_weight.amount += cpu_delta; }); } check(0 <= tot_itr->net_weight.amount, "insufficient staked total net bandwidth"); @@ -53,7 +53,32 @@ void system_contract::adjust_resources(name payer, name account, int64_t net_del } } // system_contract::adjust_resources +void system_contract::process_buybw_queue(symbol core_symbol, buybw_state& state, buybw_order_table& orders, + uint32_t max_items) { + time_point_sec now = eosio::current_time_point(); + auto idx = orders.get_index<"byexpires"_n>(); + int64_t total_net = 0; + int64_t total_cpu = 0; + while (max_items--) { + auto it = idx.begin(); + if (it == idx.end() || it->expires > now) + break; + total_net = it->net_weight; + total_cpu = it->cpu_weight; + adjust_resources(get_self(), it->owner, core_symbol, -it->net_weight, -it->cpu_weight); + idx.erase(it); + } + state.net.utilization -= total_net; + state.cpu.utilization -= total_cpu; + adjust_resources(get_self(), reserv_account, core_symbol, total_net, total_cpu, true); +} + +void system_contract::update_buybw_state(buybw_state& state) { + // +} + void system_contract::configbuybw(buybw_config& args) { + require_auth(get_self()); time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); buybw_state_singleton state_sing{ get_self(), 0 }; @@ -93,13 +118,21 @@ void system_contract::configbuybw(buybw_config& args) { update(state.net, args.net, net_delta); update(state.cpu, args.cpu, cpu_delta); - adjust_resources(get_self(), reserv_account, net_delta, cpu_delta, true); + adjust_resources(get_self(), reserv_account, core_symbol, net_delta, cpu_delta, true); state_sing.set(state, get_self()); -} +} // system_contract::configbuybw void system_contract::buybandwidth(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, const asset& max_payment) { - // + require_auth(payer); + buybw_state_singleton state_sing{ get_self(), 0 }; + buybw_order_table orders{ get_self(), 0 }; + eosio::check(state_sing.exists(), "buybandwidth hasn't been initialized"); + auto state = state_sing.get(); + auto core_symbol = get_core_symbol(); + process_buybw_queue(core_symbol, state, orders, 2); + update_buybw_state(state); + state_sing.set(state, get_self()); } } // namespace eosiosystem From 7721480e845ac116026fd8dfdd51b49dc179a63c Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 2 Dec 2019 11:14:40 -0500 Subject: [PATCH 06/78] buybandwidth --- .../include/eosio.system/eosio.system.hpp | 33 ++++++++++--------- contracts/eosio.system/src/buybandwidth.cpp | 28 +++++++++++++++- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index d497311d8..696267eec 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -488,25 +488,26 @@ namespace eosiosystem { }; struct buybw_state_resource { - uint8_t version = 0; - int64_t weight = 0; // resource market weight - int64_t initial_weight = 0; // Initial resource market weight used for linear growth - int64_t target_weight = 0; // Linearly grow the resource market weight to this amount - time_point_sec initial_timestamp = {}; // When resource market weight growth started - time_point_sec target_timestamp = {}; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. - double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). - asset total_price = {}; // Total price needed to buy the entire resource market weight. - asset min_purchase_price = {}; // Minimum purchase - int64_t utilization = 0; // Instantaneous resource utilization. This is the current amount sold. - int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. + uint8_t version = 0; + int64_t weight = 0; // resource market weight + int64_t initial_weight = 0; // Initial resource market weight used for linear growth + int64_t target_weight = 0; // Linearly grow the resource market weight to this amount + time_point_sec initial_timestamp = {}; // When resource market weight growth started + time_point_sec target_timestamp = {}; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. + double exponent = 0; // Exponent of resource price curve. + uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + asset total_price = {}; // Total price needed to buy the entire resource market weight. + asset min_purchase_price = {}; // Minimum purchase + int64_t utilization = 0; // Instantaneous resource utilization. This is the current amount sold. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. + time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; struct [[eosio::table("buybw.state"),eosio::contract("eosio.system")]] buybw_state { - uint8_t version = 0; - buybw_state_resource net = {}; // NET market state - buybw_state_resource cpu = {}; // CPU market state - uint32_t purchase_days = 0; // `buybandwidth` `days` argument must match this. + uint8_t version = 0; + buybw_state_resource net = {}; // NET market state + buybw_state_resource cpu = {}; // CPU market state + uint32_t purchase_days = 0; // `buybandwidth` `days` argument must match this. uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/buybandwidth.cpp index 2f4d1a436..eae4abb78 100644 --- a/contracts/eosio.system/src/buybandwidth.cpp +++ b/contracts/eosio.system/src/buybandwidth.cpp @@ -1,4 +1,5 @@ #include +#include namespace eosiosystem { @@ -73,8 +74,33 @@ void system_contract::process_buybw_queue(symbol core_symbol, buybw_state& state adjust_resources(get_self(), reserv_account, core_symbol, total_net, total_cpu, true); } +void update_weight(time_point_sec now, buybw_state_resource& res) { + if (now >= res.target_timestamp) + res.weight = res.target_weight; + else + res.weight = res.initial_weight + // + int128_t(res.target_weight - res.initial_weight) * + (now.utc_seconds - res.initial_timestamp.utc_seconds) / + (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); +} + +void update_utilization(time_point_sec now, buybw_state_resource& res) { + if (res.utilization >= res.adjusted_utilization) + res.adjusted_utilization = res.utilization; + else + res.adjusted_utilization = // + res.utilization + + (res.adjusted_utilization - res.utilization) * + exp((now.utc_seconds - res.utilization_timestamp.utc_seconds) / double(-res.decay_secs)); + res.utilization_timestamp = now; +} + void system_contract::update_buybw_state(buybw_state& state) { - // + time_point_sec now = eosio::current_time_point(); + update_weight(now, state.net); + update_weight(now, state.cpu); + update_utilization(now, state.net); + update_utilization(now, state.cpu); } void system_contract::configbuybw(buybw_config& args) { From 7244d2041810883ed72e395fb699949e9cd5b2df Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 2 Dec 2019 11:54:25 -0500 Subject: [PATCH 07/78] rentbw --- contracts/eosio.system/CMakeLists.txt | 2 +- .../include/eosio.system/eosio.system.hpp | 58 +++++++++--------- .../src/{buybandwidth.cpp => rentbw.cpp} | 60 +++++++++---------- ...width_tests.cpp => eosio.rentbw_tests.cpp} | 2 +- 4 files changed, 61 insertions(+), 61 deletions(-) rename contracts/eosio.system/src/{buybandwidth.cpp => rentbw.cpp} (73%) rename tests/{eosio.buybandwidth_tests.cpp => eosio.rentbw_tests.cpp} (90%) diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index 825a02d75..33f7d486e 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -1,10 +1,10 @@ add_contract(eosio.system eosio.system - ${CMAKE_CURRENT_SOURCE_DIR}/src/buybandwidth.cpp ${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/rentbw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp ) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 696267eec..f3b708e53 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -87,7 +87,7 @@ 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 resource market separate from REX: `buybandwidth` + * - A resource market separate from REX: `rentbw` */ // A name bid, which consists of: @@ -470,7 +470,7 @@ namespace eosiosystem { asset stake_change; }; - struct buybw_config_resource { + struct rentbw_config_resource { int64_t current_weight; // Immediately set the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. int64_t target_weight; // Linearly grow the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. @@ -478,16 +478,16 @@ namespace eosiosystem { double exponent; // Exponent of resource price curve. Must be >= 1. uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). asset total_price; // Total price needed to buy the entire resource market weight. - asset min_purchase_price; // Minimum purchase. This needs to be large enough to cover RAM costs. + asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover RAM costs. }; - struct buybw_config { - buybw_config_resource net; // NET market configuration - buybw_config_resource cpu; // CPU market configuration - uint32_t purchase_days; // `buybandwidth` `days` argument must match this. + struct rentbw_config { + rentbw_config_resource net; // NET market configuration + rentbw_config_resource cpu; // CPU market configuration + uint32_t rent_days; // `rentbw` `days` argument must match this. }; - struct buybw_state_resource { + struct rentbw_state_resource { uint8_t version = 0; int64_t weight = 0; // resource market weight int64_t initial_weight = 0; // Initial resource market weight used for linear growth @@ -497,24 +497,24 @@ namespace eosiosystem { double exponent = 0; // Exponent of resource price curve. uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). asset total_price = {}; // Total price needed to buy the entire resource market weight. - asset min_purchase_price = {}; // Minimum purchase + asset min_rent_price = {}; // Rents below this amount are rejected int64_t utilization = 0; // Instantaneous resource utilization. This is the current amount sold. int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; - struct [[eosio::table("buybw.state"),eosio::contract("eosio.system")]] buybw_state { - uint8_t version = 0; - buybw_state_resource net = {}; // NET market state - buybw_state_resource cpu = {}; // CPU market state - uint32_t purchase_days = 0; // `buybandwidth` `days` argument must match this. + struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { + uint8_t version = 0; + rentbw_state_resource net = {}; // NET market state + rentbw_state_resource cpu = {}; // CPU market state + uint32_t rent_days = 0; // `rentbw` `days` argument must match this. uint64_t primary_key()const { return 0; } }; - typedef eosio::singleton<"buybw.state"_n, buybw_state> buybw_state_singleton; + typedef eosio::singleton<"rent.state"_n, rentbw_state> rentbw_state_singleton; - struct [[eosio::table("buybw.order"),eosio::contract("eosio.system")]] buybw_order { + struct [[eosio::table("rentbw.order"),eosio::contract("eosio.system")]] rentbw_order { uint8_t version = 0; uint64_t id; name owner; @@ -527,10 +527,10 @@ namespace eosiosystem { uint64_t by_expires()const { return expires.utc_seconds; } }; - typedef eosio::multi_index< "buybw.order"_n, buybw_order, - indexed_by<"byowner"_n, const_mem_fun>, - indexed_by<"byexpires"_n, const_mem_fun> - > buybw_order_table; + typedef eosio::multi_index< "rentbw.order"_n, rentbw_order, + indexed_by<"byowner"_n, const_mem_fun>, + indexed_by<"byexpires"_n, const_mem_fun> + > rentbw_order_table; /** * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. @@ -1187,14 +1187,14 @@ namespace eosiosystem { void setinflation( int64_t annual_rate, int64_t inflation_pay_factor, int64_t votepay_factor ); /** - * Configure the `buybandwidth` market. The market becomes available the first time this + * Configure the `rentbw` market. The market becomes available the first time this * action is invoked. */ [[eosio::action]] - void configbuybw(buybw_config& args); + void configrentbw(rentbw_config& args); /** - * Buy NET and CPU + * Rent NET and CPU * * @param payer - the resource buyer * @param receiver - the resource receiver @@ -1205,7 +1205,7 @@ namespace eosiosystem { * `payer`'s token balance. */ [[eosio::action]] - void buybandwidth( const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, const asset& max_payment ); + void rentbw( const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, const asset& max_payment ); using init_action = eosio::action_wrapper<"init"_n, &system_contract::init>; using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; @@ -1253,8 +1253,8 @@ namespace eosiosystem { using setalimits_action = eosio::action_wrapper<"setalimits"_n, &system_contract::setalimits>; using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; - using configcpu_action = eosio::action_wrapper<"configbuybw"_n, &system_contract::configbuybw>; - using buybandwidth_action = eosio::action_wrapper<"buybandwidth"_n, &system_contract::buybandwidth>; + using configcpu_action = eosio::action_wrapper<"configrentbw"_n, &system_contract::configrentbw>; + using rentbw_action = eosio::action_wrapper<"rentbw"_n, &system_contract::rentbw>; private: // Implementation details: @@ -1356,10 +1356,10 @@ namespace eosiosystem { registration<&system_contract::update_rex_stake> vote_stake_updater{ this }; - // defined in buybandwidth.cpp + // defined in rentbw.cpp void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); - void process_buybw_queue(symbol core_symbol, buybw_state& state, buybw_order_table& orders, uint32_t max_items); - void update_buybw_state(buybw_state& state); + void process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, uint32_t max_items); + void update_rentbw_state(rentbw_state& state); }; } diff --git a/contracts/eosio.system/src/buybandwidth.cpp b/contracts/eosio.system/src/rentbw.cpp similarity index 73% rename from contracts/eosio.system/src/buybandwidth.cpp rename to contracts/eosio.system/src/rentbw.cpp index eae4abb78..3817131bf 100644 --- a/contracts/eosio.system/src/buybandwidth.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -54,8 +54,8 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym } } // system_contract::adjust_resources -void system_contract::process_buybw_queue(symbol core_symbol, buybw_state& state, buybw_order_table& orders, - uint32_t max_items) { +void system_contract::process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, + uint32_t max_items) { time_point_sec now = eosio::current_time_point(); auto idx = orders.get_index<"byexpires"_n>(); int64_t total_net = 0; @@ -74,7 +74,7 @@ void system_contract::process_buybw_queue(symbol core_symbol, buybw_state& state adjust_resources(get_self(), reserv_account, core_symbol, total_net, total_cpu, true); } -void update_weight(time_point_sec now, buybw_state_resource& res) { +void update_weight(time_point_sec now, rentbw_state_resource& res) { if (now >= res.target_timestamp) res.weight = res.target_weight; else @@ -84,7 +84,7 @@ void update_weight(time_point_sec now, buybw_state_resource& res) { (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); } -void update_utilization(time_point_sec now, buybw_state_resource& res) { +void update_utilization(time_point_sec now, rentbw_state_resource& res) { if (res.utilization >= res.adjusted_utilization) res.adjusted_utilization = res.utilization; else @@ -95,7 +95,7 @@ void update_utilization(time_point_sec now, buybw_state_resource& res) { res.utilization_timestamp = now; } -void system_contract::update_buybw_state(buybw_state& state) { +void system_contract::update_rentbw_state(rentbw_state& state) { time_point_sec now = eosio::current_time_point(); update_weight(now, state.net); update_weight(now, state.cpu); @@ -103,12 +103,12 @@ void system_contract::update_buybw_state(buybw_state& state) { update_utilization(now, state.cpu); } -void system_contract::configbuybw(buybw_config& args) { +void system_contract::configrentbw(rentbw_config& args) { require_auth(get_self()); - time_point_sec now = eosio::current_time_point(); - auto core_symbol = get_core_symbol(); - buybw_state_singleton state_sing{ get_self(), 0 }; - auto state = state_sing.get_or_default(); + time_point_sec now = eosio::current_time_point(); + auto core_symbol = get_core_symbol(); + rentbw_state_singleton state_sing{ get_self(), 0 }; + auto state = state_sing.get_or_default(); auto update = [&](auto& state, auto& args, auto& delta_weight) { if (args.current_weight == args.target_weight) @@ -121,23 +121,23 @@ void system_contract::configbuybw(buybw_config& args) { eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); eosio::check(args.total_price.symbol == core_symbol, "total_price doesn't match core symbol"); eosio::check(args.total_price.amount > 0, "total_price must be positive"); - eosio::check(args.min_purchase_price.symbol == core_symbol, "min_purchase_price doesn't match core symbol"); + eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); delta_weight = args.current_weight - state.weight; - state.weight = args.current_weight; - state.initial_weight = args.current_weight; - state.target_weight = args.target_weight; - state.initial_timestamp = now; - state.target_timestamp = args.target_timestamp; - state.exponent = args.exponent; - state.decay_secs = args.decay_secs; - state.total_price = args.total_price; - state.min_purchase_price = args.min_purchase_price; + state.weight = args.current_weight; + state.initial_weight = args.current_weight; + state.target_weight = args.target_weight; + state.initial_timestamp = now; + state.target_timestamp = args.target_timestamp; + state.exponent = args.exponent; + state.decay_secs = args.decay_secs; + state.total_price = args.total_price; + state.min_rent_price = args.min_rent_price; }; - eosio::check(args.purchase_days > 0, "purchase_days must be > 0"); - state.purchase_days = args.purchase_days; + eosio::check(args.rent_days > 0, "rent_days must be > 0"); + state.rent_days = args.rent_days; int64_t net_delta = 0; int64_t cpu_delta = 0; @@ -146,18 +146,18 @@ void system_contract::configbuybw(buybw_config& args) { adjust_resources(get_self(), reserv_account, core_symbol, net_delta, cpu_delta, true); state_sing.set(state, get_self()); -} // system_contract::configbuybw +} // system_contract::configrentbw -void system_contract::buybandwidth(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, - const asset& max_payment) { +void system_contract::rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, + const asset& max_payment) { require_auth(payer); - buybw_state_singleton state_sing{ get_self(), 0 }; - buybw_order_table orders{ get_self(), 0 }; - eosio::check(state_sing.exists(), "buybandwidth hasn't been initialized"); + rentbw_state_singleton state_sing{ get_self(), 0 }; + rentbw_order_table orders{ get_self(), 0 }; + eosio::check(state_sing.exists(), "rentbw hasn't been initialized"); auto state = state_sing.get(); auto core_symbol = get_core_symbol(); - process_buybw_queue(core_symbol, state, orders, 2); - update_buybw_state(state); + process_rentbw_queue(core_symbol, state, orders, 2); + update_rentbw_state(state); state_sing.set(state, get_self()); } diff --git a/tests/eosio.buybandwidth_tests.cpp b/tests/eosio.rentbw_tests.cpp similarity index 90% rename from tests/eosio.buybandwidth_tests.cpp rename to tests/eosio.rentbw_tests.cpp index 41ecadcb9..d71cdb8c9 100644 --- a/tests/eosio.buybandwidth_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -14,7 +14,7 @@ using namespace eosio_system; -BOOST_AUTO_TEST_SUITE(eosio_system_buybandwidth_tests) +BOOST_AUTO_TEST_SUITE(eosio_system_rentbw_tests) BOOST_FIXTURE_TEST_CASE(foo, eosio_system_tester) try { // From db44b3547c96bc1d157f87cc5bcb65f586684948 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 2 Dec 2019 18:45:20 -0500 Subject: [PATCH 08/78] rentbw --- .../include/eosio.system/eosio.system.hpp | 65 +++++++--- contracts/eosio.system/src/rentbw.cpp | 122 +++++++++++------- 2 files changed, 119 insertions(+), 68 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index f3b708e53..15c20fa4c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -40,6 +40,8 @@ namespace eosiosystem { using eosio::time_point_sec; using eosio::unsigned_int; + inline constexpr int64_t rentbw_ratio_frac = 1000000000000000ll; // 1.0 = 10^15 + template static inline auto has_field( F flags, E field ) -> std::enable_if_t< std::is_integral_v && std::is_unsigned_v && @@ -471,14 +473,28 @@ namespace eosiosystem { }; struct rentbw_config_resource { - int64_t current_weight; // Immediately set the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. - int64_t target_weight; // Linearly grow the resource market weight to this amount. 1 represents the same amount of resources as 1 satoshi of SYS staked. - time_point_sec target_timestamp; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. - // Ignored if current_weight == target_weight. + int64_t current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. Set this + // to 0 to preserve the existing setting or use the default; this avoids sudden + // price jumps. For new chains which don't need to gradually phase out staking + // and REX, 0.01x (10^13) is a good value for both current_weight_ratio and + // target_weight_ratio. + int64_t target_weight_ratio; // Linearly shrink weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. Set this + // to 0 to preserve the existing setting or use the default. + int64_t assumed_stake_weight; // Assumed stake weight for ratio calculations. Use the sum of total staked and + // total rented by REX at the time the rentbw market is first activated. Set + // this to 0 to preserve the existing setting; this avoids sudden price jumps. + // For new chains which don't need to phase out staking and REX, 10^12 is + // probably a good value. + time_point_sec target_timestamp; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. Ignored if + // current_weight_ratio == target_weight_ratio. Set this to 0 to preserve the + // existing setting. double exponent; // Exponent of resource price curve. Must be >= 1. - uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). + uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous + // utilization within exp(-1). asset total_price; // Total price needed to buy the entire resource market weight. - asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover RAM costs. + asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover + // RAM costs. }; struct rentbw_config { @@ -489,18 +505,28 @@ namespace eosiosystem { struct rentbw_state_resource { uint8_t version = 0; - int64_t weight = 0; // resource market weight - int64_t initial_weight = 0; // Initial resource market weight used for linear growth - int64_t target_weight = 0; // Linearly grow the resource market weight to this amount - time_point_sec initial_timestamp = {}; // When resource market weight growth started - time_point_sec target_timestamp = {}; // Stop automatic resource market weight growth at this time. Once this time hits, the market weight will be target_weight. - double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to decay to instantaneous utilization within exp(-1). - asset total_price = {}; // Total price needed to buy the entire resource market weight. - asset min_rent_price = {}; // Rents below this amount are rejected - int64_t utilization = 0; // Instantaneous resource utilization. This is the current amount sold. - int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It grows instantly but decays exponentially. - time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated + int64_t weight = 0; // resource market weight. calculated; varies over time. + // 1 represents the same amount of resources as 1 + // satoshi of SYS staked. + int64_t weight_ratio = 0; // resource market weight ratio: + // assumed_stake_weight / (assumed_stake_weight + weight). + // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. + int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. + int64_t initial_weight_ratio = rentbw_ratio_frac; // Initial weight_ratio used for linear shrinkage. + int64_t target_weight_ratio = rentbw_ratio_frac / 100; // Linearly shrink the weight_ratio to this amount. + time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started + time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. + double exponent = 0; // Exponent of resource price curve. + uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to + // decay to instantaneous utilization within exp(-1). + asset total_price = {}; // Total price needed to buy the entire resource market weight. + asset min_rent_price = {}; // Rents below this amount are rejected + int64_t utilization = 0; // Instantaneous resource utilization. This is the current + // amount sold. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It + // grows instantly but decays exponentially. + time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { @@ -1358,8 +1384,7 @@ namespace eosiosystem { // defined in rentbw.cpp void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); - void process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, uint32_t max_items); - void update_rentbw_state(rentbw_state& state); + void process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available); }; } diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 3817131bf..5fc0f18d2 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -55,33 +55,36 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym } // system_contract::adjust_resources void system_contract::process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, - uint32_t max_items) { - time_point_sec now = eosio::current_time_point(); - auto idx = orders.get_index<"byexpires"_n>(); - int64_t total_net = 0; - int64_t total_cpu = 0; + uint32_t max_items, int64_t& net_delta_available, + int64_t& cpu_delta_available) { + time_point_sec now = eosio::current_time_point(); + auto idx = orders.get_index<"byexpires"_n>(); while (max_items--) { auto it = idx.begin(); if (it == idx.end() || it->expires > now) break; - total_net = it->net_weight; - total_cpu = it->cpu_weight; + net_delta_available += it->net_weight; + cpu_delta_available += it->cpu_weight; adjust_resources(get_self(), it->owner, core_symbol, -it->net_weight, -it->cpu_weight); idx.erase(it); } - state.net.utilization -= total_net; - state.cpu.utilization -= total_cpu; - adjust_resources(get_self(), reserv_account, core_symbol, total_net, total_cpu, true); + state.net.utilization -= net_delta_available; + state.cpu.utilization -= cpu_delta_available; } -void update_weight(time_point_sec now, rentbw_state_resource& res) { +void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available) { if (now >= res.target_timestamp) - res.weight = res.target_weight; + res.weight_ratio = res.target_weight_ratio; else - res.weight = res.initial_weight + // - int128_t(res.target_weight - res.initial_weight) * - (now.utc_seconds - res.initial_timestamp.utc_seconds) / - (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); + res.weight_ratio = res.initial_weight_ratio + // + int128_t(res.target_weight_ratio - res.initial_weight_ratio) * + (now.utc_seconds - res.initial_timestamp.utc_seconds) / + (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); + + int64_t new_weight = + res.assumed_stake_weight * int128_t(rentbw_ratio_frac) / res.weight_ratio - res.assumed_stake_weight; + delta_available += new_weight - res.weight; + res.weight = new_weight; } void update_utilization(time_point_sec now, rentbw_state_resource& res) { @@ -95,14 +98,6 @@ void update_utilization(time_point_sec now, rentbw_state_resource& res) { res.utilization_timestamp = now; } -void system_contract::update_rentbw_state(rentbw_state& state) { - time_point_sec now = eosio::current_time_point(); - update_weight(now, state.net); - update_weight(now, state.cpu); - update_utilization(now, state.net); - update_utilization(now, state.cpu); -} - void system_contract::configrentbw(rentbw_config& args) { require_auth(get_self()); time_point_sec now = eosio::current_time_point(); @@ -110,41 +105,59 @@ void system_contract::configrentbw(rentbw_config& args) { rentbw_state_singleton state_sing{ get_self(), 0 }; auto state = state_sing.get_or_default(); - auto update = [&](auto& state, auto& args, auto& delta_weight) { - if (args.current_weight == args.target_weight) + int64_t net_delta_available = 0; + int64_t cpu_delta_available = 0; + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); + + auto update = [&](auto& state, auto& args) { + if (!args.current_weight_ratio) + args.current_weight_ratio = state.weight_ratio; + if (!args.target_weight_ratio) + args.target_weight_ratio = state.target_weight_ratio; + if (!args.assumed_stake_weight) + args.assumed_stake_weight = state.assumed_stake_weight; + if (!args.target_timestamp.utc_seconds) + args.target_timestamp = state.target_timestamp; + + if (args.current_weight_ratio == args.target_weight_ratio) args.target_timestamp = now; else eosio::check(args.target_timestamp > now, "target_timestamp must be in the future"); - eosio::check(args.target_weight >= args.current_weight, "weight can't shrink over time"); - eosio::check(args.current_weight >= state.utilization, "weight can't shrink below utilization"); + eosio::check(args.current_weight_ratio > 0, "current_weight_ratio is too small"); + eosio::check(args.current_weight_ratio <= rentbw_ratio_frac, "current_weight_ratio is too large"); + eosio::check(args.target_weight_ratio <= args.current_weight_ratio, "weight can't grow over time"); + eosio::check(args.assumed_stake_weight >= 1, + "assumed_stake_weight must be at least 1; a much larger value is recommended"); eosio::check(args.exponent >= 1, "exponent must be >= 1"); eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); eosio::check(args.total_price.symbol == core_symbol, "total_price doesn't match core symbol"); eosio::check(args.total_price.amount > 0, "total_price must be positive"); eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); - delta_weight = args.current_weight - state.weight; - - state.weight = args.current_weight; - state.initial_weight = args.current_weight; - state.target_weight = args.target_weight; - state.initial_timestamp = now; - state.target_timestamp = args.target_timestamp; - state.exponent = args.exponent; - state.decay_secs = args.decay_secs; - state.total_price = args.total_price; - state.min_rent_price = args.min_rent_price; + state.assumed_stake_weight = args.assumed_stake_weight; + state.initial_weight_ratio = args.current_weight_ratio; + state.target_weight_ratio = args.target_weight_ratio; + state.initial_timestamp = now; + state.target_timestamp = args.target_timestamp; + state.exponent = args.exponent; + state.decay_secs = args.decay_secs; + state.total_price = args.total_price; + state.min_rent_price = args.min_rent_price; }; eosio::check(args.rent_days > 0, "rent_days must be > 0"); state.rent_days = args.rent_days; - int64_t net_delta = 0; - int64_t cpu_delta = 0; - update(state.net, args.net, net_delta); - update(state.cpu, args.cpu, cpu_delta); + update(state.net, args.net); + update(state.cpu, args.cpu); - adjust_resources(get_self(), reserv_account, core_symbol, net_delta, cpu_delta, true); + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); + eosio::check(state.net.weight >= state.net.utilization, "weight can't shrink below utilization"); + eosio::check(state.cpu.weight >= state.cpu.utilization, "weight can't shrink below utilization"); + + adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); } // system_contract::configrentbw @@ -154,10 +167,23 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d rentbw_state_singleton state_sing{ get_self(), 0 }; rentbw_order_table orders{ get_self(), 0 }; eosio::check(state_sing.exists(), "rentbw hasn't been initialized"); - auto state = state_sing.get(); - auto core_symbol = get_core_symbol(); - process_rentbw_queue(core_symbol, state, orders, 2); - update_rentbw_state(state); + auto state = state_sing.get(); + time_point_sec now = eosio::current_time_point(); + auto core_symbol = get_core_symbol(); + eosio::check(max_payment.symbol == core_symbol, "max_payment doesn't match core symbol"); + + int64_t net_delta_available = 0; + int64_t cpu_delta_available = 0; + process_rentbw_queue(core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); + update_utilization(now, state.net); + update_utilization(now, state.cpu); + + // todo: rent + // todo: check against min_rent_price + + adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); } From 04a98eb5c15f79df6e2c2086bd4ad55a9f20363e Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 3 Dec 2019 13:56:38 -0500 Subject: [PATCH 09/78] rentbw --- .../include/eosio.system/eosio.system.hpp | 18 ++++++--- contracts/eosio.system/src/rentbw.cpp | 40 ++++++++++++++----- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 15c20fa4c..6b7d41914 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -489,18 +489,21 @@ namespace eosiosystem { // time hits, weight_ratio will be target_weight_ratio. Ignored if // current_weight_ratio == target_weight_ratio. Set this to 0 to preserve the // existing setting. - double exponent; // Exponent of resource price curve. Must be >= 1. + double exponent; // Exponent of resource price curve. Must be >= 1. Set this to 0 to preserve the + // existing setting. uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous - // utilization within exp(-1). - asset total_price; // Total price needed to buy the entire resource market weight. + // utilization within exp(-1). Set this to 0 to preserve the existing setting. + asset total_price; // Total price needed to buy the entire resource market weight. Set this to 0 to + // preserve the existing setting. asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover - // RAM costs. + // RAM costs. Set this to 0 to preserve the existing setting. }; struct rentbw_config { rentbw_config_resource net; // NET market configuration rentbw_config_resource cpu; // CPU market configuration - uint32_t rent_days; // `rentbw` `days` argument must match this. + uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the + // existing setting. }; struct rentbw_state_resource { @@ -1384,7 +1387,10 @@ namespace eosiosystem { // defined in rentbw.cpp void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); - void process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available); + void process_rentbw_queue( + time_point_sec now, symbol core_symbol, rentbw_state& state, + rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, + int64_t& cpu_delta_available); }; } diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 5fc0f18d2..593c831df 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -54,11 +54,10 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym } } // system_contract::adjust_resources -void system_contract::process_rentbw_queue(symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, - uint32_t max_items, int64_t& net_delta_available, +void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbol, rentbw_state& state, + rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available) { - time_point_sec now = eosio::current_time_point(); - auto idx = orders.get_index<"byexpires"_n>(); + auto idx = orders.get_index<"byexpires"_n>(); while (max_items--) { auto it = idx.begin(); if (it == idx.end() || it->expires > now) @@ -80,7 +79,7 @@ void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delt int128_t(res.target_weight_ratio - res.initial_weight_ratio) * (now.utc_seconds - res.initial_timestamp.utc_seconds) / (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); - + // !!! check bounds of weight_ratio int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_ratio_frac) / res.weight_ratio - res.assumed_stake_weight; delta_available += new_weight - res.weight; @@ -107,25 +106,41 @@ void system_contract::configrentbw(rentbw_config& args) { int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - update_weight(now, state.net, net_delta_available); - update_weight(now, state.cpu, cpu_delta_available); + if (state_sing.exists()) { + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); + } auto update = [&](auto& state, auto& args) { - if (!args.current_weight_ratio) - args.current_weight_ratio = state.weight_ratio; + if (!args.current_weight_ratio) { + if (state.weight_ratio) + args.current_weight_ratio = state.weight_ratio; + else + args.current_weight_ratio = state.initial_weight_ratio; + } if (!args.target_weight_ratio) args.target_weight_ratio = state.target_weight_ratio; if (!args.assumed_stake_weight) args.assumed_stake_weight = state.assumed_stake_weight; if (!args.target_timestamp.utc_seconds) args.target_timestamp = state.target_timestamp; - + if (!args.exponent) + args.exponent = state.exponent; + if (!args.decay_secs) + args.decay_secs = state.decay_secs; + if (!args.total_price.amount) + args.total_price = state.total_price; + if (!args.min_rent_price.amount) + args.min_rent_price = state.min_rent_price; + + // !!! examine checks if (args.current_weight_ratio == args.target_weight_ratio) args.target_timestamp = now; else eosio::check(args.target_timestamp > now, "target_timestamp must be in the future"); eosio::check(args.current_weight_ratio > 0, "current_weight_ratio is too small"); eosio::check(args.current_weight_ratio <= rentbw_ratio_frac, "current_weight_ratio is too large"); + eosio::check(args.target_weight_ratio > 0, "target_weight_ratio is too small"); eosio::check(args.target_weight_ratio <= args.current_weight_ratio, "weight can't grow over time"); eosio::check(args.assumed_stake_weight >= 1, "assumed_stake_weight must be at least 1; a much larger value is recommended"); @@ -134,6 +149,7 @@ void system_contract::configrentbw(rentbw_config& args) { eosio::check(args.total_price.symbol == core_symbol, "total_price doesn't match core symbol"); eosio::check(args.total_price.amount > 0, "total_price must be positive"); eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); + eosio::check(args.min_rent_price.amount > 0, "min_rent_price must be positive"); state.assumed_stake_weight = args.assumed_stake_weight; state.initial_weight_ratio = args.current_weight_ratio; @@ -146,6 +162,8 @@ void system_contract::configrentbw(rentbw_config& args) { state.min_rent_price = args.min_rent_price; }; + if (!args.rent_days) + args.rent_days = state.rent_days; eosio::check(args.rent_days > 0, "rent_days must be > 0"); state.rent_days = args.rent_days; @@ -174,7 +192,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - process_rentbw_queue(core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); + process_rentbw_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); update_weight(now, state.net, net_delta_available); update_weight(now, state.cpu, cpu_delta_available); update_utilization(now, state.net); From 04cf097e9b0f71c4ae1babfb111d7a1e10fe29be Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 3 Dec 2019 18:13:12 -0500 Subject: [PATCH 10/78] rentbw --- .../include/eosio.system/eosio.system.hpp | 70 +++++++++---------- contracts/eosio.system/src/rentbw.cpp | 69 +++++++++++++----- contracts/eosio.system/src/rex.cpp | 4 +- 3 files changed, 90 insertions(+), 53 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6b7d41914..94dae3627 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -40,8 +40,8 @@ namespace eosiosystem { using eosio::time_point_sec; using eosio::unsigned_int; - inline constexpr int64_t rentbw_ratio_frac = 1000000000000000ll; // 1.0 = 10^15 - + inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 + template static inline auto has_field( F flags, E field ) -> std::enable_if_t< std::is_integral_v && std::is_unsigned_v && @@ -493,43 +493,42 @@ namespace eosiosystem { // existing setting. uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous // utilization within exp(-1). Set this to 0 to preserve the existing setting. - asset total_price; // Total price needed to buy the entire resource market weight. Set this to 0 to + asset target_price; // Fee needed to rent the entire resource market weight. Set this to 0 to // preserve the existing setting. - asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover - // RAM costs. Set this to 0 to preserve the existing setting. }; struct rentbw_config { - rentbw_config_resource net; // NET market configuration - rentbw_config_resource cpu; // CPU market configuration - uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the - // existing setting. + rentbw_config_resource net; // NET market configuration + rentbw_config_resource cpu; // CPU market configuration + uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the + // existing setting. + asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover + // RAM costs. Set this to 0 to preserve the existing setting. }; struct rentbw_state_resource { uint8_t version = 0; - int64_t weight = 0; // resource market weight. calculated; varies over time. - // 1 represents the same amount of resources as 1 - // satoshi of SYS staked. - int64_t weight_ratio = 0; // resource market weight ratio: - // assumed_stake_weight / (assumed_stake_weight + weight). - // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. - int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. - int64_t initial_weight_ratio = rentbw_ratio_frac; // Initial weight_ratio used for linear shrinkage. - int64_t target_weight_ratio = rentbw_ratio_frac / 100; // Linearly shrink the weight_ratio to this amount. - time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started - time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this - // time hits, weight_ratio will be target_weight_ratio. - double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to - // decay to instantaneous utilization within exp(-1). - asset total_price = {}; // Total price needed to buy the entire resource market weight. - asset min_rent_price = {}; // Rents below this amount are rejected - int64_t utilization = 0; // Instantaneous resource utilization. This is the current - // amount sold. - int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It - // grows instantly but decays exponentially. - time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated + int64_t weight = 0; // resource market weight. calculated; varies over time. + // 1 represents the same amount of resources as 1 + // satoshi of SYS staked. + int64_t weight_ratio = 0; // resource market weight ratio: + // assumed_stake_weight / (assumed_stake_weight + weight). + // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. + int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. + int64_t initial_weight_ratio = rentbw_frac; // Initial weight_ratio used for linear shrinkage. + int64_t target_weight_ratio = rentbw_frac / 100; // Linearly shrink the weight_ratio to this amount. + time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started + time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. + double exponent = 0; // Exponent of resource price curve. + uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to + // decay to instantaneous utilization within exp(-1). + asset target_price = {}; // Fee needed to rent the entire resource market weight. + int64_t utilization = 0; // Instantaneous resource utilization. This is the current + // amount sold. utilization <= weight. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It + // grows instantly but decays exponentially. + time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { @@ -537,6 +536,7 @@ namespace eosiosystem { rentbw_state_resource net = {}; // NET market state rentbw_state_resource cpu = {}; // CPU market state uint32_t rent_days = 0; // `rentbw` `days` argument must match this. + asset min_rent_price = {}; // Rents below this amount are rejected uint64_t primary_key()const { return 0; } }; @@ -1228,13 +1228,13 @@ namespace eosiosystem { * @param payer - the resource buyer * @param receiver - the resource receiver * @param days - number of days of resource availability. Must match market configuration. - * @param net - fraction of net (100% = 10^18) managed by this market - * @param cpu - fraction of cpu (100% = 10^18) managed by this market + * @param net_frac - fraction of net (100% = 10^15) managed by this market + * @param cpu_frac - fraction of cpu (100% = 10^15) managed by this market * @param max_payment - the maximum amount `payer` is willing to pay. Tokens are withdrawn from * `payer`'s token balance. */ [[eosio::action]] - void rentbw( const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, const asset& max_payment ); + void rentbw( const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment ); using init_action = eosio::action_wrapper<"init"_n, &system_contract::init>; using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; @@ -1308,7 +1308,7 @@ namespace eosiosystem { const char* error_msg = "must vote for at least 21 producers or for a proxy before buying REX" )const; rex_order_outcome fill_rex_order( const rex_balance_table::const_iterator& bitr, const asset& rex ); asset update_rex_account( const name& owner, const asset& proceeds, const asset& unstake_quant, bool force_vote_update = false ); - void channel_to_rex( const name& from, const asset& amount ); + void channel_to_rex( const name& from, const asset& amount, bool required = false ); void channel_namebid_to_rex( const int64_t highest_bid ); template int64_t rent_rex( T& table, const name& from, const name& receiver, const asset& loan_payment, const asset& loan_fund ); diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 593c831df..cca3173ef 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -80,8 +80,7 @@ void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delt (now.utc_seconds - res.initial_timestamp.utc_seconds) / (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); // !!! check bounds of weight_ratio - int64_t new_weight = - res.assumed_stake_weight * int128_t(rentbw_ratio_frac) / res.weight_ratio - res.assumed_stake_weight; + int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_frac) / res.weight_ratio - res.assumed_stake_weight; delta_available += new_weight - res.weight; res.weight = new_weight; } @@ -128,10 +127,8 @@ void system_contract::configrentbw(rentbw_config& args) { args.exponent = state.exponent; if (!args.decay_secs) args.decay_secs = state.decay_secs; - if (!args.total_price.amount) - args.total_price = state.total_price; - if (!args.min_rent_price.amount) - args.min_rent_price = state.min_rent_price; + if (!args.target_price.amount) + args.target_price = state.target_price; // !!! examine checks if (args.current_weight_ratio == args.target_weight_ratio) @@ -139,17 +136,15 @@ void system_contract::configrentbw(rentbw_config& args) { else eosio::check(args.target_timestamp > now, "target_timestamp must be in the future"); eosio::check(args.current_weight_ratio > 0, "current_weight_ratio is too small"); - eosio::check(args.current_weight_ratio <= rentbw_ratio_frac, "current_weight_ratio is too large"); + eosio::check(args.current_weight_ratio <= rentbw_frac, "current_weight_ratio is too large"); eosio::check(args.target_weight_ratio > 0, "target_weight_ratio is too small"); eosio::check(args.target_weight_ratio <= args.current_weight_ratio, "weight can't grow over time"); eosio::check(args.assumed_stake_weight >= 1, "assumed_stake_weight must be at least 1; a much larger value is recommended"); eosio::check(args.exponent >= 1, "exponent must be >= 1"); eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); - eosio::check(args.total_price.symbol == core_symbol, "total_price doesn't match core symbol"); - eosio::check(args.total_price.amount > 0, "total_price must be positive"); - eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); - eosio::check(args.min_rent_price.amount > 0, "min_rent_price must be positive"); + eosio::check(args.target_price.symbol == core_symbol, "target_price doesn't match core symbol"); + eosio::check(args.target_price.amount > 0, "target_price must be positive"); state.assumed_stake_weight = args.assumed_stake_weight; state.initial_weight_ratio = args.current_weight_ratio; @@ -158,14 +153,20 @@ void system_contract::configrentbw(rentbw_config& args) { state.target_timestamp = args.target_timestamp; state.exponent = args.exponent; state.decay_secs = args.decay_secs; - state.total_price = args.total_price; - state.min_rent_price = args.min_rent_price; + state.target_price = args.target_price; }; if (!args.rent_days) args.rent_days = state.rent_days; + if (!args.min_rent_price.amount) + args.min_rent_price = state.min_rent_price; + eosio::check(args.rent_days > 0, "rent_days must be > 0"); - state.rent_days = args.rent_days; + eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); + eosio::check(args.min_rent_price.amount > 0, "min_rent_price must be positive"); + + state.rent_days = args.rent_days; + state.min_rent_price = args.min_rent_price; update(state.net, args.net); update(state.cpu, args.cpu); @@ -179,7 +180,11 @@ void system_contract::configrentbw(rentbw_config& args) { state_sing.set(state, get_self()); } // system_contract::configrentbw -void system_contract::rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net, int64_t cpu, +int64_t calc_rentbw_price(const rentbw_state_resource& state, double utilization) { + return ceil(state.target_price.amount * pow(utilization / state.weight, state.exponent)); +} + +void system_contract::rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment) { require_auth(payer); rentbw_state_singleton state_sing{ get_self(), 0 }; @@ -189,6 +194,11 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); eosio::check(max_payment.symbol == core_symbol, "max_payment doesn't match core symbol"); + eosio::check(days == state.rent_days, "days doesn't match configuration"); + eosio::check(net_frac >= 0, "net_frac can't be negative"); + eosio::check(cpu_frac >= 0, "cpu_frac can't be negative"); + eosio::check(net_frac <= rentbw_frac, "net can't be more than 100%"); + eosio::check(cpu_frac <= rentbw_frac, "cpu can't be more than 100%"); int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; @@ -198,10 +208,35 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d update_utilization(now, state.net); update_utilization(now, state.cpu); - // todo: rent - // todo: check against min_rent_price + eosio::asset fee{ 0, core_symbol }; + auto process = [&](int64_t frac, int64_t& amount, rentbw_state_resource& state) { + if (!frac) + return; + amount = int128_t(frac) * state.weight / rentbw_frac; + fee += calc_rentbw_price(state, state.adjusted_utilization + amount) - + calc_rentbw_price(state, state.adjusted_utilization); + state.utilization += amount; + eosio::check(state.utilization <= state.weight, "market doesn't have enough resources available"); + }; + int64_t net_amount = 0; + int64_t cpu_amount = 0; + process(net_frac, net_amount, state.net); + process(cpu_frac, cpu_amount, state.cpu); + eosio::check(fee <= max_payment, "calculated fee exceeds max_payment"); + eosio::check(fee >= state.min_rent_price, "calculated fee is below minimum; try renting more"); + + orders.emplace([&](payer, auto& order) { + order.id = orders.available_primary_key(); + order.owner = receiver; + order.net_weight = net_amount; + order.cpu_weight = cpu_amount; + order.expires = now + eosio::days(days); + }); + + adjust_resources(payer, receiver, core_symbol, net, cpu, true); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); + channel_to_rex(payer, fee, true); state_sing.set(state, get_self()); } diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 8e9d881f3..bcc8868db 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -917,7 +917,7 @@ namespace eosiosystem { * @param from - account from which asset is transfered to REX pool * @param amount - amount of tokens to be transfered */ - void system_contract::channel_to_rex( const name& from, const asset& amount ) + void system_contract::channel_to_rex( const name& from, const asset& amount, bool required ) { #if CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX if ( rex_available() ) { @@ -926,8 +926,10 @@ namespace eosiosystem { token::transfer_action transfer_act{ token_account, { from, active_permission } }; transfer_act.send( from, rex_account, amount, std::string("transfer from ") + from.to_string() + " to eosio.rex" ); + return; } #endif + eosio::check( !required, "can't channel fees to rex" ); } /** From 3c6f5823b3cf1c959ce55e7902d5caa8e725550e Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 4 Dec 2019 13:59:49 -0500 Subject: [PATCH 11/78] testing --- .../include/eosio.system/eosio.system.hpp | 2 +- contracts/eosio.system/src/rentbw.cpp | 12 +- tests/eosio.rentbw_tests.cpp | 126 +++++++++++++++++- 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 94dae3627..2e219cd04 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -41,7 +41,7 @@ namespace eosiosystem { using eosio::unsigned_int; inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 - + template static inline auto has_field( F flags, E field ) -> std::enable_if_t< std::is_integral_v && std::is_unsigned_v && diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index cca3173ef..cad25115e 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -127,7 +127,7 @@ void system_contract::configrentbw(rentbw_config& args) { args.exponent = state.exponent; if (!args.decay_secs) args.decay_secs = state.decay_secs; - if (!args.target_price.amount) + if (!args.target_price.amount && state.target_price.amount) args.target_price = state.target_price; // !!! examine checks @@ -158,7 +158,7 @@ void system_contract::configrentbw(rentbw_config& args) { if (!args.rent_days) args.rent_days = state.rent_days; - if (!args.min_rent_price.amount) + if (!args.min_rent_price.amount && state.min_rent_price.amount) args.min_rent_price = state.min_rent_price; eosio::check(args.rent_days > 0, "rent_days must be > 0"); @@ -213,8 +213,8 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d if (!frac) return; amount = int128_t(frac) * state.weight / rentbw_frac; - fee += calc_rentbw_price(state, state.adjusted_utilization + amount) - - calc_rentbw_price(state, state.adjusted_utilization); + fee.amount += calc_rentbw_price(state, state.adjusted_utilization + amount) - + calc_rentbw_price(state, state.adjusted_utilization); state.utilization += amount; eosio::check(state.utilization <= state.weight, "market doesn't have enough resources available"); }; @@ -226,7 +226,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d eosio::check(fee <= max_payment, "calculated fee exceeds max_payment"); eosio::check(fee >= state.min_rent_price, "calculated fee is below minimum; try renting more"); - orders.emplace([&](payer, auto& order) { + orders.emplace(payer, [&](auto& order) { order.id = orders.available_primary_key(); order.owner = receiver; order.net_weight = net_amount; @@ -234,7 +234,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d order.expires = now + eosio::days(days); }); - adjust_resources(payer, receiver, core_symbol, net, cpu, true); + adjust_resources(payer, receiver, core_symbol, net_amount, cpu_amount, true); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); channel_to_rex(payer, fee, true); state_sing.set(state, get_self()); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index d71cdb8c9..b3c38a9dc 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -12,13 +12,135 @@ #include "eosio.system_tester.hpp" +inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 +inline constexpr int64_t stake_weight = 1000000000000ll; // 10^12 + +struct rentbw_config_resource { + int64_t current_weight_ratio = {}; + int64_t target_weight_ratio = {}; + int64_t assumed_stake_weight = {}; + time_point_sec target_timestamp = {}; + double exponent = {}; + uint32_t decay_secs = {}; + asset target_price = asset{}; +}; +FC_REFLECT(rentbw_config_resource, // + (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight)(target_timestamp) // + (exponent)(decay_secs)(target_price)) + +struct rentbw_config { + rentbw_config_resource net = {}; + rentbw_config_resource cpu = {}; + uint32_t rent_days = {}; + asset min_rent_price = asset{}; +}; +FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_price)) + using namespace eosio_system; +struct rentbw_tester : eosio_system_tester { + + template + rentbw_config make_config(F f) { + rentbw_config config; + + config.net.current_weight_ratio = rentbw_frac; + config.net.target_weight_ratio = rentbw_frac / 100; + config.net.assumed_stake_weight = stake_weight; + config.net.target_timestamp = control->head_block_time() + fc::days(100); + config.net.exponent = 2; + config.net.decay_secs = fc::days(1).to_seconds(); + config.net.target_price = asset::from_string("1000000.0000 TST"); + + config.cpu.current_weight_ratio = rentbw_frac; + config.cpu.target_weight_ratio = rentbw_frac / 100; + config.cpu.assumed_stake_weight = stake_weight; + config.cpu.target_timestamp = control->head_block_time() + fc::days(100); + config.cpu.exponent = 2; + config.cpu.decay_secs = fc::days(1).to_seconds(); + config.cpu.target_price = asset::from_string("1000000.0000 TST"); + + config.rent_days = 30; + config.min_rent_price = asset::from_string("1.0000 TST"); + + f(config); + return config; + } + + rentbw_config make_config() { + return make_config([](auto&) {}); + } + + action_result configbw(const rentbw_config& config) { + return push_action(N(eosio), N(configrentbw), mvo()("args", config)); + } +}; + BOOST_AUTO_TEST_SUITE(eosio_system_rentbw_tests) -BOOST_FIXTURE_TEST_CASE(foo, eosio_system_tester) try { - // +BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { + BOOST_REQUIRE_EQUAL("missing authority of eosio", + push_action(N(alice1111111), N(configrentbw), mvo()("args", make_config()))); + + BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), + configbw(make_config([&](auto& c) { c.rent_days = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.min_rent_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), + configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), + configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("-1.0000 TST"); }))); + + // net assertions + BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), + configbw(make_config([](auto& c) { c.net.current_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), + configbw(make_config([](auto& c) { c.net.target_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), + configbw(make_config([](auto& c) { c.net.assumed_stake_weight = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), + configbw(make_config([&](auto& c) { c.net.target_timestamp = control->head_block_time(); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { + c.net.target_timestamp = control->head_block_time() - fc::seconds(1); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), + configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.net.target_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("-1.0000 TST"); }))); + + // cpu assertions + BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), + configbw(make_config([](auto& c) { c.cpu.current_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), + configbw(make_config([](auto& c) { c.cpu.target_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), + configbw(make_config([](auto& c) { c.cpu.assumed_stake_weight = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), + configbw(make_config([&](auto& c) { c.cpu.target_timestamp = control->head_block_time(); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { + c.cpu.target_timestamp = control->head_block_time() - fc::seconds(1); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), + configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.cpu.target_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); } + FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() From e9aed5f45ade5a3f5b05f1c0eba3ce0185a9c5c7 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 4 Dec 2019 18:54:29 -0500 Subject: [PATCH 12/78] testing --- .../include/eosio.system/eosio.system.hpp | 11 ++- contracts/eosio.system/src/rentbw.cpp | 21 ++++++ tests/eosio.rentbw_tests.cpp | 69 ++++++++++++++++++- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2e219cd04..8a2859df1 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1220,7 +1220,16 @@ namespace eosiosystem { * action is invoked. */ [[eosio::action]] - void configrentbw(rentbw_config& args); + void configrentbw( rentbw_config& args ); + + /** + * Process rentbw queue and update state. Action does not execute anything related to a specific user. + * + * @param user - any account can execute this action + * @param max - number of queue items to process + */ + [[eosio::action]] + void rentbwexec( const name& user, uint16_t max ); /** * Rent NET and CPU diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index cad25115e..2d5d43eda 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -184,6 +184,27 @@ int64_t calc_rentbw_price(const rentbw_state_resource& state, double utilization return ceil(state.target_price.amount * pow(utilization / state.weight, state.exponent)); } +void system_contract::rentbwexec(const name& user, uint16_t max) { + require_auth(user); + rentbw_state_singleton state_sing{ get_self(), 0 }; + rentbw_order_table orders{ get_self(), 0 }; + eosio::check(state_sing.exists(), "rentbw hasn't been initialized"); + auto state = state_sing.get(); + time_point_sec now = eosio::current_time_point(); + auto core_symbol = get_core_symbol(); + + int64_t net_delta_available = 0; + int64_t cpu_delta_available = 0; + process_rentbw_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); + update_utilization(now, state.net); + update_utilization(now, state.cpu); + + adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); + state_sing.set(state, get_self()); +} + void system_contract::rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment) { require_auth(payer); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index b3c38a9dc..605150681 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -36,10 +36,42 @@ struct rentbw_config { }; FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_price)) +struct rentbw_state_resource { + uint8_t version; + int64_t weight; + int64_t weight_ratio; + int64_t assumed_stake_weight; + int64_t initial_weight_ratio; + int64_t target_weight_ratio; + time_point_sec initial_timestamp; + time_point_sec target_timestamp; + double exponent; + uint32_t decay_secs; + asset target_price; + int64_t utilization; + int64_t adjusted_utilization; + time_point_sec utilization_timestamp; +}; +FC_REFLECT(rentbw_state_resource, // + (version)(weight)(weight_ratio)(assumed_stake_weight)(initial_weight_ratio)(target_weight_ratio) // + (initial_timestamp)(target_timestamp)(exponent)(decay_secs)(target_price)(utilization) // + (adjusted_utilization)(utilization_timestamp)) + +struct rentbw_state { + uint8_t version; + rentbw_state_resource net; + rentbw_state_resource cpu; + uint32_t rent_days; + asset min_rent_price; +}; +FC_REFLECT(rentbw_state, (version)(net)(cpu)(rent_days)(min_rent_price)) + using namespace eosio_system; struct rentbw_tester : eosio_system_tester { + rentbw_tester() { create_accounts_with_resources({ N(eosio.reserv) }); } + template rentbw_config make_config(F f) { rentbw_config config; @@ -72,7 +104,16 @@ struct rentbw_tester : eosio_system_tester { } action_result configbw(const rentbw_config& config) { - return push_action(N(eosio), N(configrentbw), mvo()("args", config)); + return push_action(config::system_account_name, N(configrentbw), mvo()("args", config)); + } + + action_result rentbwexec(name user, uint16_t max) { + return push_action(user, N(rentbwexec), mvo()("user", user)("max", max)); + } + + rentbw_state get_state() { + vector data = get_row_by_account(config::system_account_name, {}, N(rent.state), N(rent.state)); + return fc::raw::unpack(data); } }; @@ -81,6 +122,7 @@ BOOST_AUTO_TEST_SUITE(eosio_system_rentbw_tests) BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL("missing authority of eosio", push_action(N(alice1111111), N(configrentbw), mvo()("args", make_config()))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("rentbw hasn't been initialized"), rentbwexec(N(alice1111111), 10)); BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), configbw(make_config([&](auto& c) { c.rent_days = 0; }))); @@ -139,8 +181,33 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); + + // TODO: "weight can't shrink below utilization" } +FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { + produce_block(); + + BOOST_REQUIRE_EQUAL("", configbw(make_config([&](rentbw_config& config) { + config.net.current_weight_ratio = (rentbw_frac * 11) / 100; + config.net.target_weight_ratio = (rentbw_frac * 1) / 100; + config.net.assumed_stake_weight = stake_weight; + config.net.target_timestamp = control->head_block_time() + fc::days(10); + config.cpu.current_weight_ratio = (rentbw_frac * 11) / 1000; + config.cpu.target_weight_ratio = (rentbw_frac * 1) / 1000; + config.cpu.assumed_stake_weight = stake_weight; + config.cpu.target_timestamp = control->head_block_time() + fc::days(10); + }))); + + for (int i = 11; i >= 1; --i) { + BOOST_REQUIRE_EQUAL(get_state().net.weight_ratio, (rentbw_frac * i) / 100); + BOOST_REQUIRE_EQUAL(get_state().cpu.weight_ratio, (rentbw_frac * i) / 1000); + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + } +} FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() From 93a8c08da7b0d2bbbb8ddc83304cb7245db0c500 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Thu, 5 Dec 2019 15:50:41 -0500 Subject: [PATCH 13/78] tests --- tests/eosio.rentbw_tests.cpp | 126 ++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 10 deletions(-) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 605150681..518c56c75 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -103,6 +103,13 @@ struct rentbw_tester : eosio_system_tester { return make_config([](auto&) {}); } + template + rentbw_config make_default_config(F f) { + rentbw_config config; + f(config); + return config; + } + action_result configbw(const rentbw_config& config) { return push_action(config::system_account_name, N(configrentbw), mvo()("args", config)); } @@ -117,6 +124,14 @@ struct rentbw_tester : eosio_system_tester { } }; +template +bool near(A a, B b, D delta) { + if (abs(a - b) <= delta) + return true; + elog("near: ${a} ${b}", ("a", a)("b", b)); + return false; +} + BOOST_AUTO_TEST_SUITE(eosio_system_rentbw_tests) BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { @@ -183,31 +198,122 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); // TODO: "weight can't shrink below utilization" -} +} // config_tests FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { produce_block(); + auto net_start = (rentbw_frac * 11) / 100; + auto net_target = (rentbw_frac * 1) / 100; + auto cpu_start = (rentbw_frac * 11) / 1000; + auto cpu_target = (rentbw_frac * 1) / 1000; + BOOST_REQUIRE_EQUAL("", configbw(make_config([&](rentbw_config& config) { - config.net.current_weight_ratio = (rentbw_frac * 11) / 100; - config.net.target_weight_ratio = (rentbw_frac * 1) / 100; + config.net.current_weight_ratio = net_start; + config.net.target_weight_ratio = net_target; config.net.assumed_stake_weight = stake_weight; config.net.target_timestamp = control->head_block_time() + fc::days(10); - config.cpu.current_weight_ratio = (rentbw_frac * 11) / 1000; - config.cpu.target_weight_ratio = (rentbw_frac * 1) / 1000; + config.cpu.current_weight_ratio = cpu_start; + config.cpu.target_weight_ratio = cpu_target; config.cpu.assumed_stake_weight = stake_weight; - config.cpu.target_timestamp = control->head_block_time() + fc::days(10); + config.cpu.target_timestamp = control->head_block_time() + fc::days(20); }))); - for (int i = 11; i >= 1; --i) { - BOOST_REQUIRE_EQUAL(get_state().net.weight_ratio, (rentbw_frac * i) / 100); - BOOST_REQUIRE_EQUAL(get_state().cpu.weight_ratio, (rentbw_frac * i) / 1000); + int64_t net; + int64_t cpu; + + for (int i = 0; i <= 6; ++i) { + if (i == 2) { + // Leaves everything as-is, but may introduce slight rounding + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", configbw({})); + } else if (i) { + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + } + net = net_start + i * (net_target - net_start) / 10; + cpu = cpu_start + i * (cpu_target - cpu_start) / 20; + BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + } + + // Extend transition time + { + int i = 7; + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + config.net.target_timestamp = control->head_block_time() + fc::days(30); + config.cpu.target_timestamp = control->head_block_time() + fc::days(40); + }))); + net_start = net = net_start + i * (net_target - net_start) / 10; + cpu_start = cpu = cpu_start + i * (cpu_target - cpu_start) / 20; + BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + } + + for (int i = 0; i <= 5; ++i) { + if (i) { + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + } + net = net_start + i * (net_target - net_start) / 30; + cpu = cpu_start + i * (cpu_target - cpu_start) / 40; + BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + } + + // Change target, keep existing transition time + { + int i = 6; + produce_block(fc::days(1) - fc::milliseconds(500)); + auto new_net_target = net_target / 10; + auto new_cpu_target = cpu_target / 20; + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + config.net.target_weight_ratio = new_net_target; + config.cpu.target_weight_ratio = new_cpu_target; + }))); + net_start = net = net_start + i * (net_target - net_start) / 30; + cpu_start = cpu = cpu_start + i * (cpu_target - cpu_start) / 40; + net_target = new_net_target; + cpu_target = new_cpu_target; + BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + } + + for (int i = 0; i <= 10; ++i) { + if (i) { + produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + } + net = net_start + i * (net_target - net_start) / (30 - 6); + cpu = cpu_start + i * (cpu_target - cpu_start) / (40 - 6); + BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + } + + // Move transition time to immediate future + { produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + config.net.target_timestamp = control->head_block_time() + fc::milliseconds(1000); + config.cpu.target_timestamp = control->head_block_time() + fc::milliseconds(1000); + }))); + produce_blocks(2); + } + + // Verify targets hold as time advances + for (int i = 0; i <= 10; ++i) { BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(get_state().net.weight_ratio, net_target, 1)); + BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu_target, 1)); + produce_block(fc::days(1)); } -} + + // todo: verify calculated weight + +} // weight_tests FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() From 518381f97562a0f37a98c0d7533e311b53770976 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Thu, 5 Dec 2019 16:14:02 -0500 Subject: [PATCH 14/78] tests --- tests/eosio.rentbw_tests.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 518c56c75..f1bd0c6c9 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -224,9 +224,18 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { int64_t net; int64_t cpu; + auto check_weight = [&] { + auto state = get_state(); + BOOST_REQUIRE(near( // + state.net.weight_ratio, // + int64_t(state.net.assumed_stake_weight * eosio::chain::int128_t(rentbw_frac) / + (state.net.weight + state.net.assumed_stake_weight)), + 10)); + }; + for (int i = 0; i <= 6; ++i) { if (i == 2) { - // Leaves everything as-is, but may introduce slight rounding + // Leaves config as-is, but may introduce slight rounding produce_block(fc::days(1) - fc::milliseconds(500)); BOOST_REQUIRE_EQUAL("", configbw({})); } else if (i) { @@ -237,6 +246,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { cpu = cpu_start + i * (cpu_target - cpu_start) / 20; BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + check_weight(); } // Extend transition time @@ -251,6 +261,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { cpu_start = cpu = cpu_start + i * (cpu_target - cpu_start) / 20; BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + check_weight(); } for (int i = 0; i <= 5; ++i) { @@ -262,6 +273,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { cpu = cpu_start + i * (cpu_target - cpu_start) / 40; BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + check_weight(); } // Change target, keep existing transition time @@ -280,6 +292,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { cpu_target = new_cpu_target; BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + check_weight(); } for (int i = 0; i <= 10; ++i) { @@ -291,6 +304,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { cpu = cpu_start + i * (cpu_target - cpu_start) / (40 - 6); BOOST_REQUIRE(near(get_state().net.weight_ratio, net, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu, 1)); + check_weight(); } // Move transition time to immediate future @@ -308,11 +322,9 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); BOOST_REQUIRE(near(get_state().net.weight_ratio, net_target, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu_target, 1)); + check_weight(); produce_block(fc::days(1)); } - - // todo: verify calculated weight - } // weight_tests FC_LOG_AND_RETHROW() From a02c3efd8bf8b4c67e9383d4986b01bb6e388191 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 6 Dec 2019 14:37:12 -0500 Subject: [PATCH 15/78] tests --- contracts/eosio.system/src/rentbw.cpp | 9 +- tests/eosio.rentbw_tests.cpp | 136 ++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 2d5d43eda..73d5da5b0 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -234,10 +234,13 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d if (!frac) return; amount = int128_t(frac) * state.weight / rentbw_frac; - fee.amount += calc_rentbw_price(state, state.adjusted_utilization + amount) - - calc_rentbw_price(state, state.adjusted_utilization); + eosio::check(state.weight, "market doesn't have resources available"); + eosio::check(state.utilization + amount <= state.weight, "market doesn't have enough resources available"); + int64_t f = calc_rentbw_price(state, state.adjusted_utilization + amount) - + calc_rentbw_price(state, state.adjusted_utilization); + eosio::check(f > 0, "calculated fee is below minimum; try renting more"); + fee.amount += f; state.utilization += amount; - eosio::check(state.utilization <= state.weight, "market doesn't have enough resources available"); }; int64_t net_amount = 0; diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index f1bd0c6c9..ee9fa7208 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -72,6 +72,23 @@ struct rentbw_tester : eosio_system_tester { rentbw_tester() { create_accounts_with_resources({ N(eosio.reserv) }); } + void start_rex() { + create_account_with_resources(N(rexholder111), config::system_account_name, core_sym::from_string("1.0000"), + false); + transfer(config::system_account_name, N(rexholder111), core_sym::from_string("1001.0000")); + BOOST_REQUIRE_EQUAL("", stake(N(rexholder111), N(rexholder111), core_sym::from_string("500.0000"), + core_sym::from_string("500.0000"))); + create_account_with_resources(N(proxyaccount), config::system_account_name, core_sym::from_string("1.0000"), + false, core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + BOOST_REQUIRE_EQUAL("", + push_action(N(proxyaccount), N(regproxy), mvo()("proxy", "proxyaccount")("isproxy", true))); + BOOST_REQUIRE_EQUAL("", vote(N(rexholder111), {}, N(proxyaccount))); + BOOST_REQUIRE_EQUAL("", push_action(N(rexholder111), N(deposit), + mvo()("owner", "rexholder111")("amount", asset::from_string("1.0000 TST")))); + BOOST_REQUIRE_EQUAL("", push_action(N(rexholder111), N(buyrex), + mvo()("from", "rexholder111")("amount", asset::from_string("1.0000 TST")))); + } + template rentbw_config make_config(F f) { rentbw_config config; @@ -118,10 +135,53 @@ struct rentbw_tester : eosio_system_tester { return push_action(user, N(rentbwexec), mvo()("user", user)("max", max)); } + action_result rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, + const asset& max_payment) { + return push_action(payer, N(rentbw), + mvo()("payer", payer)("receiver", receiver)("days", days)("net_frac", net_frac)( + "cpu_frac", cpu_frac)("max_payment", max_payment)); + } + rentbw_state get_state() { vector data = get_row_by_account(config::system_account_name, {}, N(rent.state), N(rent.state)); return fc::raw::unpack(data); } + + struct account_info { + int64_t ram = 0; + int64_t net = 0; + int64_t cpu = 0; + asset liquid; + }; + + account_info get_account_info(account_name acc) { + account_info info; + control->get_resource_limits_manager().get_account_limits(acc, info.ram, info.net, info.cpu); + info.liquid = get_balance(acc); + return info; + }; + + void check_rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, + const asset& max_payment) { + auto before_payer = get_account_info(payer); + auto before_receiver = get_account_info(receiver); + auto before_state = get_state(); + BOOST_REQUIRE_EQUAL("", rentbw(payer, receiver, days, net_frac, cpu_frac, max_payment)); + auto after_payer = get_account_info(payer); + auto after_receiver = get_account_info(receiver); + auto after_state = get_state(); + + if (payer != receiver) { + BOOST_REQUIRE(before_payer.ram == after_payer.ram); + BOOST_REQUIRE(before_payer.net == after_payer.net); + BOOST_REQUIRE(before_payer.cpu == after_payer.cpu); + BOOST_REQUIRE(before_receiver.liquid == after_receiver.liquid); + } + BOOST_REQUIRE(before_receiver.ram == after_receiver.ram); + // BOOST_REQUIRE(before_receiver.net == after_receiver.net); + // BOOST_REQUIRE(before_receiver.cpu == after_receiver.cpu); + // BOOST_REQUIRE(before_payer.liquid == after_payer.liquid); + } }; template @@ -328,4 +388,80 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { } // weight_tests FC_LOG_AND_RETHROW() +BOOST_AUTO_TEST_CASE(rent_tests) try { + rentbw_tester t; + t.produce_block(); + + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("rentbw hasn't been initialized"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 4, rentbw_frac / 8, + asset::from_string("1.000 TST"))); + + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { + config.net.current_weight_ratio = rentbw_frac; + config.net.target_weight_ratio = rentbw_frac; + config.net.assumed_stake_weight = stake_weight; + config.net.exponent = 1; + config.net.target_price = asset::from_string("1000000.0000 TST"); + + config.cpu.current_weight_ratio = rentbw_frac; + config.cpu.target_weight_ratio = rentbw_frac; + config.cpu.assumed_stake_weight = stake_weight; + config.cpu.exponent = 1; + config.cpu.target_price = asset::from_string("1000000.0000 TST"); + + config.rent_days = 30; + config.min_rent_price = asset::from_string("1.0000 TST"); + }))); + + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("max_payment doesn't match core symbol"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.000 TST"))); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("market doesn't have resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, 0, rentbw_frac, asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("market doesn't have resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, 0, asset::from_string("1.0000 TST"))); + + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { + // weight = stake_weight * 3/4 + config.net.current_weight_ratio = rentbw_frac / 4; + config.net.target_weight_ratio = rentbw_frac / 4; + config.net.assumed_stake_weight = stake_weight; + config.net.exponent = 2; + config.net.target_price = asset::from_string("1000000.0000 TST"); + + // weight = stake_weight * 4/5 * 1/2 + config.cpu.current_weight_ratio = rentbw_frac / 5; + config.cpu.target_weight_ratio = rentbw_frac / 5; + config.cpu.assumed_stake_weight = stake_weight / 2; + config.cpu.exponent = 3; + config.cpu.target_price = asset::from_string("2000000.0000 TST"); + + config.rent_days = 30; + config.min_rent_price = asset::from_string("1.0000 TST"); + }))); + + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("calculated fee exceeds max_payment"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("can't channel fees to rex"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, + asset::from_string("3000000.0000 TST"))); + + t.start_rex(); + t.create_account_with_resources(N(aaaaaaaaaaaa), config::system_account_name, core_sym::from_string("1.0000"), false, + core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + t.create_account_with_resources(N(bbbbbbbbbbbb), config::system_account_name, core_sym::from_string("1.0000"), false, + core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); + BOOST_REQUIRE_EQUAL("", t.rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + asset::from_string("3000000.0000 TST"))); + + // todo: calculated fee is below minimum; try renting more + +} // rent_tests +FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() From 07dd2d374a18afb6266fc695cc5e683502592518 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 6 Dec 2019 16:57:24 -0500 Subject: [PATCH 16/78] tests --- tests/eosio.rentbw_tests.cpp | 210 ++++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 79 deletions(-) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index ee9fa7208..ee1d7ce7e 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -13,7 +13,7 @@ #include "eosio.system_tester.hpp" inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 -inline constexpr int64_t stake_weight = 1000000000000ll; // 10^12 +inline constexpr int64_t stake_weight = 100'000'000'0000ll; // 10^12 struct rentbw_config_resource { int64_t current_weight_ratio = {}; @@ -162,25 +162,40 @@ struct rentbw_tester : eosio_system_tester { }; void check_rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, - const asset& max_payment) { + const asset& expected_fee, int64_t expected_net, int64_t expected_cpu) { auto before_payer = get_account_info(payer); auto before_receiver = get_account_info(receiver); auto before_state = get_state(); - BOOST_REQUIRE_EQUAL("", rentbw(payer, receiver, days, net_frac, cpu_frac, max_payment)); + BOOST_REQUIRE_EQUAL("", rentbw(payer, receiver, days, net_frac, cpu_frac, expected_fee)); auto after_payer = get_account_info(payer); auto after_receiver = get_account_info(receiver); auto after_state = get_state(); + if (false) { + ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); + ilog("before_state.net.weight_ratio: ${x}", + ("x", before_state.net.weight_ratio / double(rentbw_frac))); + ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); + ilog("before_state.net.weight: ${x}", ("x", before_state.net.weight)); + + ilog("before_receiver.net: ${x}", ("x", before_receiver.net)); + ilog("after_receiver.net: ${x}", ("x", after_receiver.net)); + ilog("after_receiver.net - before_receiver.net: ${x}", ("x", after_receiver.net - before_receiver.net)); + ilog("expected_net: ${x}", ("x", expected_net)); + ilog("before_payer.liquid - after_payer.liquid: ${x}", ("x", before_payer.liquid - after_payer.liquid)); + ilog("expected_fee: ${x}", ("x", expected_fee)); + } + if (payer != receiver) { - BOOST_REQUIRE(before_payer.ram == after_payer.ram); - BOOST_REQUIRE(before_payer.net == after_payer.net); - BOOST_REQUIRE(before_payer.cpu == after_payer.cpu); - BOOST_REQUIRE(before_receiver.liquid == after_receiver.liquid); + BOOST_REQUIRE_EQUAL(before_payer.ram, after_payer.ram); + BOOST_REQUIRE_EQUAL(before_payer.net, after_payer.net); + BOOST_REQUIRE_EQUAL(before_payer.cpu, after_payer.cpu); + BOOST_REQUIRE_EQUAL(before_receiver.liquid, after_receiver.liquid); } - BOOST_REQUIRE(before_receiver.ram == after_receiver.ram); - // BOOST_REQUIRE(before_receiver.net == after_receiver.net); - // BOOST_REQUIRE(before_receiver.cpu == after_receiver.cpu); - // BOOST_REQUIRE(before_payer.liquid == after_payer.liquid); + BOOST_REQUIRE_EQUAL(before_receiver.ram, after_receiver.ram); + BOOST_REQUIRE_EQUAL(before_receiver.net, after_receiver.net - expected_net); + BOOST_REQUIRE_EQUAL(before_receiver.cpu, after_receiver.cpu - expected_cpu); + BOOST_REQUIRE_EQUAL(before_payer.liquid - after_payer.liquid, expected_fee); } }; @@ -389,78 +404,115 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_CASE(rent_tests) try { - rentbw_tester t; - t.produce_block(); - - BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("rentbw hasn't been initialized"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 4, rentbw_frac / 8, - asset::from_string("1.000 TST"))); - - BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { - config.net.current_weight_ratio = rentbw_frac; - config.net.target_weight_ratio = rentbw_frac; - config.net.assumed_stake_weight = stake_weight; - config.net.exponent = 1; - config.net.target_price = asset::from_string("1000000.0000 TST"); - - config.cpu.current_weight_ratio = rentbw_frac; - config.cpu.target_weight_ratio = rentbw_frac; - config.cpu.assumed_stake_weight = stake_weight; - config.cpu.exponent = 1; - config.cpu.target_price = asset::from_string("1000000.0000 TST"); - - config.rent_days = 30; - config.min_rent_price = asset::from_string("1.0000 TST"); - }))); - - BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("max_payment doesn't match core symbol"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.000 TST"))); - BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("market doesn't have resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, 0, rentbw_frac, asset::from_string("1.0000 TST"))); - BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("market doesn't have resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, 0, asset::from_string("1.0000 TST"))); - - BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { - // weight = stake_weight * 3/4 - config.net.current_weight_ratio = rentbw_frac / 4; - config.net.target_weight_ratio = rentbw_frac / 4; - config.net.assumed_stake_weight = stake_weight; - config.net.exponent = 2; - config.net.target_price = asset::from_string("1000000.0000 TST"); - - // weight = stake_weight * 4/5 * 1/2 - config.cpu.current_weight_ratio = rentbw_frac / 5; - config.cpu.target_weight_ratio = rentbw_frac / 5; - config.cpu.assumed_stake_weight = stake_weight / 2; - config.cpu.exponent = 3; - config.cpu.target_price = asset::from_string("2000000.0000 TST"); - - config.rent_days = 30; - config.min_rent_price = asset::from_string("1.0000 TST"); - }))); - - BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("calculated fee exceeds max_payment"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); - BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("can't channel fees to rex"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, - asset::from_string("3000000.0000 TST"))); + { + rentbw_tester t; + t.produce_block(); + + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("rentbw hasn't been initialized"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 4, rentbw_frac / 8, + asset::from_string("1.000 TST"))); + + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { + config.net.current_weight_ratio = rentbw_frac; + config.net.target_weight_ratio = rentbw_frac; + config.net.assumed_stake_weight = stake_weight; + config.net.exponent = 1; + config.net.target_price = asset::from_string("1000000.0000 TST"); + + config.cpu.current_weight_ratio = rentbw_frac; + config.cpu.target_weight_ratio = rentbw_frac; + config.cpu.assumed_stake_weight = stake_weight; + config.cpu.exponent = 1; + config.cpu.target_price = asset::from_string("1000000.0000 TST"); + + config.rent_days = 30; + config.min_rent_price = asset::from_string("1.0000 TST"); + }))); + + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("max_payment doesn't match core symbol"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.000 TST"))); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("market doesn't have resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, 0, rentbw_frac, asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("market doesn't have resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, 0, asset::from_string("1.0000 TST"))); + } - t.start_rex(); - t.create_account_with_resources(N(aaaaaaaaaaaa), config::system_account_name, core_sym::from_string("1.0000"), false, - core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); - t.create_account_with_resources(N(bbbbbbbbbbbb), config::system_account_name, core_sym::from_string("1.0000"), false, - core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + auto init = [](auto& t, bool rex) { + t.produce_block(); + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { + // weight = stake_weight * 3 + config.net.current_weight_ratio = rentbw_frac / 4; + config.net.target_weight_ratio = rentbw_frac / 4; + config.net.assumed_stake_weight = stake_weight; + config.net.exponent = 2; + config.net.target_price = asset::from_string("1000000.0000 TST"); + + // weight = stake_weight * 4 / 2 + config.cpu.current_weight_ratio = rentbw_frac / 5; + config.cpu.target_weight_ratio = rentbw_frac / 5; + config.cpu.assumed_stake_weight = stake_weight / 2; + config.cpu.exponent = 3; + config.cpu.target_price = asset::from_string("2000000.0000 TST"); + + config.rent_days = 30; + config.min_rent_price = asset::from_string("1.0000 TST"); + }))); + + if (rex) + t.start_rex(); + + t.create_account_with_resources(N(aaaaaaaaaaaa), config::system_account_name, core_sym::from_string("1.0000"), + false, core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + t.create_account_with_resources(N(bbbbbbbbbbbb), config::system_account_name, core_sym::from_string("1.0000"), + false, core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + }; + auto net_weight = stake_weight * 3; + auto cpu_weight = stake_weight * 4 / 2; - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); - BOOST_REQUIRE_EQUAL("", t.rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, - asset::from_string("3000000.0000 TST"))); + { + rentbw_tester t; + init(t, false); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("calculated fee exceeds max_payment"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("can't channel fees to rex"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, + asset::from_string("3000000.0000 TST"))); + } - // todo: calculated fee is below minimum; try renting more + // net:100%, cpu:100% + { + rentbw_tester t; + init(t, true); + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("calculated fee is below minimum; try renting more"), + t.rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, 10, 10, asset::from_string("3000000.0000 TST"))); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); + } + // net:30%, cpu:40%, then net:5%, cpu:10% + { + rentbw_tester t; + init(t, true); + // (.3 ^ 2) * 1000000.0000 = 90000.0000 + // (.4 ^ 3) * 2000000.0000 = 128000.0000 + // total = 218000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("218000.0001")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .3, rentbw_frac * .4, + asset::from_string("218000.0001 TST"), net_weight * .3, cpu_weight * .4); + + // (.35 ^ 2) * 1000000.0000 - 90000.0000 = 32500.0000 + // (.5 ^ 3) * 2000000.0000 - 128000.0000 = 122000.0000 + // total = 154500.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("154499.9999")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .05, rentbw_frac * .10, + asset::from_string("154499.9999 TST"), net_weight * .05, cpu_weight * .10); + } } // rent_tests FC_LOG_AND_RETHROW() From 0a6ca897a45ae56910f1cb9ee3f7485d322dbec9 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 6 Dec 2019 17:36:09 -0500 Subject: [PATCH 17/78] Fix eosio.reserve --- contracts/eosio.system/src/rentbw.cpp | 2 ++ tests/eosio.rentbw_tests.cpp | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 73d5da5b0..fbf13566b 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -257,6 +257,8 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d order.cpu_weight = cpu_amount; order.expires = now + eosio::days(days); }); + net_delta_available -= net_amount; + cpu_delta_available -= cpu_amount; adjust_resources(payer, receiver, core_symbol, net_amount, cpu_amount, true); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index ee1d7ce7e..23f85defa 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -165,13 +165,15 @@ struct rentbw_tester : eosio_system_tester { const asset& expected_fee, int64_t expected_net, int64_t expected_cpu) { auto before_payer = get_account_info(payer); auto before_receiver = get_account_info(receiver); + auto before_reserve = get_account_info(N(eosio.reserv)); auto before_state = get_state(); BOOST_REQUIRE_EQUAL("", rentbw(payer, receiver, days, net_frac, cpu_frac, expected_fee)); auto after_payer = get_account_info(payer); auto after_receiver = get_account_info(receiver); + auto after_reserve = get_account_info(N(eosio.reserv)); auto after_state = get_state(); - if (false) { + if (true) { ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); ilog("before_state.net.weight_ratio: ${x}", ("x", before_state.net.weight_ratio / double(rentbw_frac))); @@ -184,6 +186,11 @@ struct rentbw_tester : eosio_system_tester { ilog("expected_net: ${x}", ("x", expected_net)); ilog("before_payer.liquid - after_payer.liquid: ${x}", ("x", before_payer.liquid - after_payer.liquid)); ilog("expected_fee: ${x}", ("x", expected_fee)); + + ilog("before_reserve.net: ${x}", ("x", before_reserve.net)); + ilog("after_reserve.net: ${x}", ("x", after_reserve.net)); + ilog("before_reserve.cpu: ${x}", ("x", before_reserve.cpu)); + ilog("after_reserve.cpu: ${x}", ("x", after_reserve.cpu)); } if (payer != receiver) { @@ -193,9 +200,12 @@ struct rentbw_tester : eosio_system_tester { BOOST_REQUIRE_EQUAL(before_receiver.liquid, after_receiver.liquid); } BOOST_REQUIRE_EQUAL(before_receiver.ram, after_receiver.ram); - BOOST_REQUIRE_EQUAL(before_receiver.net, after_receiver.net - expected_net); - BOOST_REQUIRE_EQUAL(before_receiver.cpu, after_receiver.cpu - expected_cpu); + BOOST_REQUIRE_EQUAL(after_receiver.net - before_receiver.net, expected_net); + BOOST_REQUIRE_EQUAL(after_receiver.cpu - before_receiver.cpu, expected_cpu); BOOST_REQUIRE_EQUAL(before_payer.liquid - after_payer.liquid, expected_fee); + + BOOST_REQUIRE_EQUAL(before_reserve.net - after_reserve.net, expected_net); + BOOST_REQUIRE_EQUAL(before_reserve.cpu - after_reserve.cpu, expected_cpu); } }; From 9673ab0d6b0d9f0049a870a4b1f4fc9b61952cfe Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 9 Dec 2019 11:40:33 -0500 Subject: [PATCH 18/78] fix utilization update order --- contracts/eosio.system/src/rentbw.cpp | 15 +++++++-------- tests/eosio.rentbw_tests.cpp | 4 +++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index fbf13566b..f40db80e9 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -3,6 +3,9 @@ namespace eosiosystem { +void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available); +void update_utilization(time_point_sec now, rentbw_state_resource& res); + void system_contract::adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed) { if (!net_delta && !cpu_delta) @@ -57,6 +60,8 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbol, rentbw_state& state, rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available) { + update_utilization(now, state.net); + update_utilization(now, state.cpu); auto idx = orders.get_index<"byexpires"_n>(); while (max_items--) { auto it = idx.begin(); @@ -69,6 +74,8 @@ void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbo } state.net.utilization -= net_delta_available; state.cpu.utilization -= cpu_delta_available; + update_weight(now, state.net, net_delta_available); + update_weight(now, state.cpu, cpu_delta_available); } void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available) { @@ -196,10 +203,6 @@ void system_contract::rentbwexec(const name& user, uint16_t max) { int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; process_rentbw_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); - update_weight(now, state.net, net_delta_available); - update_weight(now, state.cpu, cpu_delta_available); - update_utilization(now, state.net); - update_utilization(now, state.cpu); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); @@ -224,10 +227,6 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; process_rentbw_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); - update_weight(now, state.net, net_delta_available); - update_weight(now, state.cpu, cpu_delta_available); - update_utilization(now, state.net); - update_utilization(now, state.cpu); eosio::asset fee{ 0, core_symbol }; auto process = [&](int64_t frac, int64_t& amount, rentbw_state_resource& state) { diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 23f85defa..b2705b1c3 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -173,7 +173,7 @@ struct rentbw_tester : eosio_system_tester { auto after_reserve = get_account_info(N(eosio.reserv)); auto after_state = get_state(); - if (true) { + if (false) { ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); ilog("before_state.net.weight_ratio: ${x}", ("x", before_state.net.weight_ratio / double(rentbw_frac))); @@ -206,6 +206,8 @@ struct rentbw_tester : eosio_system_tester { BOOST_REQUIRE_EQUAL(before_reserve.net - after_reserve.net, expected_net); BOOST_REQUIRE_EQUAL(before_reserve.cpu - after_reserve.cpu, expected_cpu); + BOOST_REQUIRE_EQUAL(after_state.net.utilization - before_state.net.utilization, expected_net); + BOOST_REQUIRE_EQUAL(after_state.cpu.utilization - before_state.cpu.utilization, expected_cpu); } }; From b86accc2f3aa511c2beea5e3d07c26fb19079390 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 9 Dec 2019 17:48:14 -0500 Subject: [PATCH 19/78] Fix adjusted_utilization --- contracts/eosio.system/src/rentbw.cpp | 2 +- tests/eosio.rentbw_tests.cpp | 69 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index f40db80e9..9c6699a62 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -99,7 +99,7 @@ void update_utilization(time_point_sec now, rentbw_state_resource& res) { res.adjusted_utilization = // res.utilization + (res.adjusted_utilization - res.utilization) * - exp((now.utc_seconds - res.utilization_timestamp.utc_seconds) / double(-res.decay_secs)); + exp(-double(now.utc_seconds - res.utilization_timestamp.utc_seconds) / double(res.decay_secs)); res.utilization_timestamp = now; } diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index b2705b1c3..1ae7872ad 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -525,6 +525,75 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .05, rentbw_frac * .10, asset::from_string("154499.9999 TST"), net_weight * .05, cpu_weight * .10); } + + { + // net:100%, cpu:100% + rentbw_tester t; + init(t, true); + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); + + // No more available for 30 days + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + t.produce_block(fc::days(29)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + t.produce_block(fc::days(1) - fc::milliseconds(1500)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + t.produce_block(fc::milliseconds(500)); + + // immediate renewal: adjusted_utilization doesn't have time to fall + // + // (2.0 ^ 2) * 1000000.0000 - 1000000.0000 = 3000000.0000 + // (2.0 ^ 3) * 2000000.0000 - 2000000.0000 = 14000000.0000 + // total = 17000000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("17000000.0000")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + asset::from_string("17000000.0000 TST"), 0, 0); + + // No more available for 30 days + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + t.produce_block(fc::days(29)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + t.produce_block(fc::days(1) - fc::milliseconds(1000)); + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + asset::from_string("1.0000 TST"))); + + // Start decay + t.produce_block(fc::milliseconds(1000)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, net_weight, net_weight / 1000)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, cpu_weight, cpu_weight / 1000)); + + // 1 day of decay + t.produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(net_weight * exp(-1)), + int64_t(net_weight * exp(-1)) / 1000)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(cpu_weight * exp(-1)), + int64_t(cpu_weight * exp(-1)) / 1000)); + + // 1 day of decay + t.produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(net_weight * exp(-2)), + int64_t(net_weight * exp(-2)) / 1000)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(cpu_weight * exp(-2)), + int64_t(cpu_weight * exp(-2)) / 1000)); + } + } // rent_tests FC_LOG_AND_RETHROW() From cc7ab5225356dd890a4ce9a4cecc2b0dc63f05d6 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Mon, 9 Dec 2019 19:03:30 -0500 Subject: [PATCH 20/78] tests --- tests/eosio.rentbw_tests.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 1ae7872ad..a92dcf0fd 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -592,6 +592,15 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { int64_t(net_weight * exp(-2)) / 1000)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(cpu_weight * exp(-2)), int64_t(cpu_weight * exp(-2)) / 1000)); + + // 100% after 2 days of decay + // + // [((e^-2 + 1.0) ^ 2) - ((e^-2) ^ 2) ] * 1000000.0000 = 1270670.5664 + // [((e^-2 + 1.0) ^ 3) - ((e^-2) ^ 3) ] * 2000000.0000 = 2921905.5327 + // total = 4192576.0991 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("4192561.0244")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + asset::from_string("4192561.0244 TST"), net_weight, cpu_weight); } } // rent_tests From 1030f8427242cf17f0d48fe467964a5db226d3c7 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 10 Dec 2019 13:36:22 -0500 Subject: [PATCH 21/78] tests --- tests/eosio.rentbw_tests.cpp | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index a92dcf0fd..fece8839f 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -603,6 +603,52 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { asset::from_string("4192561.0244 TST"), net_weight, cpu_weight); } + { + rentbw_tester t; + init(t, true); + + // 10%, 20% + // (.1 ^ 2) * 1000000.0000 = 10000.0000 + // (.2 ^ 3) * 2000000.0000 = 16000.0000 + // total = 26000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("26000.0002")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .1, rentbw_frac * .2, + asset::from_string("26000.0002 TST"), net_weight * .1, cpu_weight * .2); + + t.produce_block(fc::days(15) - fc::milliseconds(500)); + + // 20%, 20% + // (.3 ^ 2) * 1000000.0000 - 10000.0000 = 80000.0000 + // (.4 ^ 3) * 2000000.0000 - 16000.0000 = 112000.0000 + // total = 192000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("191999.9999")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .2, rentbw_frac * .2, + asset::from_string("191999.9999 TST"), net_weight * .2, cpu_weight * .2); + + // Start decay + t.produce_block(fc::days(15) - fc::milliseconds(1000)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, .3 * net_weight, 0)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, .4 * cpu_weight, 0)); + + // 1 day of decay from (30%, 40%) to (20%, 20%) + t.produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE( + near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-1) + .2 * net_weight), 0)); + BOOST_REQUIRE( + near(t.get_state().cpu.adjusted_utilization, int64_t(.2 * cpu_weight * exp(-1) + .2 * cpu_weight), 0)); + + // 2 days of decay from (30%, 40%) to (20%, 20%) + t.produce_block(fc::days(1) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE( + near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-2) + .2 * net_weight), 0)); + BOOST_REQUIRE( + near(t.get_state().cpu.adjusted_utilization, int64_t(.2 * cpu_weight * exp(-2) + .2 * cpu_weight), 0)); + } + } // rent_tests FC_LOG_AND_RETHROW() From f87dae900a452aaef599108c4ff65218b2dcf8a7 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Tue, 10 Dec 2019 18:13:23 -0500 Subject: [PATCH 22/78] prevent weight from getting too large --- contracts/eosio.system/src/rentbw.cpp | 5 +++-- tests/eosio.rentbw_tests.cpp | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 9c6699a62..4476b5ba2 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -86,7 +86,6 @@ void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delt int128_t(res.target_weight_ratio - res.initial_weight_ratio) * (now.utc_seconds - res.initial_timestamp.utc_seconds) / (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); - // !!! check bounds of weight_ratio int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_frac) / res.weight_ratio - res.assumed_stake_weight; delta_available += new_weight - res.weight; res.weight = new_weight; @@ -137,7 +136,6 @@ void system_contract::configrentbw(rentbw_config& args) { if (!args.target_price.amount && state.target_price.amount) args.target_price = state.target_price; - // !!! examine checks if (args.current_weight_ratio == args.target_weight_ratio) args.target_timestamp = now; else @@ -148,6 +146,9 @@ void system_contract::configrentbw(rentbw_config& args) { eosio::check(args.target_weight_ratio <= args.current_weight_ratio, "weight can't grow over time"); eosio::check(args.assumed_stake_weight >= 1, "assumed_stake_weight must be at least 1; a much larger value is recommended"); + eosio::check(args.assumed_stake_weight * int128_t(rentbw_frac) / args.target_weight_ratio <= + std::numeric_limits::max(), + "assumed_stake_weight/target_weight_ratio is too large"); eosio::check(args.exponent >= 1, "exponent must be >= 1"); eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); eosio::check(args.target_price.symbol == core_symbol, "target_price doesn't match core symbol"); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index fece8839f..04b10437e 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -239,6 +239,11 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { // net assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), configbw(make_config([](auto& c) { c.net.current_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight/target_weight_ratio is too large"), + configbw(make_config([](auto& c) { + c.net.assumed_stake_weight = 100000; + c.net.target_weight_ratio = 10; + }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), configbw(make_config([](auto& c) { c.net.target_weight_ratio = rentbw_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), @@ -263,6 +268,11 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { // cpu assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), configbw(make_config([](auto& c) { c.cpu.current_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight/target_weight_ratio is too large"), + configbw(make_config([](auto& c) { + c.cpu.assumed_stake_weight = 100000; + c.cpu.target_weight_ratio = 10; + }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), configbw(make_config([](auto& c) { c.cpu.target_weight_ratio = rentbw_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), @@ -283,11 +293,19 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); - - // TODO: "weight can't shrink below utilization" } // config_tests FC_LOG_AND_RETHROW() +/* TODO: + +eosio::check(days == state.rent_days, "days doesn't match configuration"); +eosio::check(net_frac >= 0, "net_frac can't be negative"); +eosio::check(cpu_frac >= 0, "cpu_frac can't be negative"); +eosio::check(net_frac <= rentbw_frac, "net can't be more than 100%"); +eosio::check(cpu_frac <= rentbw_frac, "cpu can't be more than 100%"); +eosio::check(state.net.weight >= state.net.utilization, "weight can't shrink below utilization"); +*/ + BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { produce_block(); From e5889cdfb1bfd02826e4455db86e13c523e457b2 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 11 Dec 2019 11:20:12 -0500 Subject: [PATCH 23/78] tests --- tests/eosio.rentbw_tests.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 04b10437e..6af225234 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -298,11 +298,6 @@ FC_LOG_AND_RETHROW() /* TODO: -eosio::check(days == state.rent_days, "days doesn't match configuration"); -eosio::check(net_frac >= 0, "net_frac can't be negative"); -eosio::check(cpu_frac >= 0, "cpu_frac can't be negative"); -eosio::check(net_frac <= rentbw_frac, "net can't be more than 100%"); -eosio::check(cpu_frac <= rentbw_frac, "cpu can't be more than 100%"); eosio::check(state.net.weight >= state.net.utilization, "weight can't shrink below utilization"); */ @@ -505,6 +500,25 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { { rentbw_tester t; init(t, false); + BOOST_REQUIRE_EQUAL( + t.wasm_assert_msg("days doesn't match configuration"), // + t.rentbw(N(bob111111111), N(alice1111111), 20, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("net_frac can't be negative"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, -rentbw_frac, rentbw_frac, + asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("cpu_frac can't be negative"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, -rentbw_frac, + asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("net can't be more than 100%"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac + 1, rentbw_frac, + asset::from_string("1.0000 TST"))); + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("cpu can't be more than 100%"), // + t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac + 1, + asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("calculated fee exceeds max_payment"), // t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); From 5b7f15ed09280d43c4813466fbe3ac6995edbd8e Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 11 Dec 2019 11:35:42 -0500 Subject: [PATCH 24/78] tests --- tests/eosio.rentbw_tests.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 6af225234..4306ce383 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -296,11 +296,6 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { } // config_tests FC_LOG_AND_RETHROW() -/* TODO: - -eosio::check(state.net.weight >= state.net.utilization, "weight can't shrink below utilization"); -*/ - BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { produce_block(); @@ -537,6 +532,31 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { t.rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, 10, 10, asset::from_string("3000000.0000 TST"))); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); + + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("weight can't shrink below utilization"), + t.configbw(t.make_default_config([&](auto& config) { + config.net.current_weight_ratio = rentbw_frac / 4 + 1; + config.net.target_weight_ratio = rentbw_frac / 4 + 1; + config.cpu.current_weight_ratio = rentbw_frac / 5; + config.cpu.target_weight_ratio = rentbw_frac / 5; + }))); + BOOST_REQUIRE_EQUAL( // + t.wasm_assert_msg("weight can't shrink below utilization"), + t.configbw(t.make_default_config([&](auto& config) { + config.net.current_weight_ratio = rentbw_frac / 4; + config.net.target_weight_ratio = rentbw_frac / 4; + config.cpu.current_weight_ratio = rentbw_frac / 5 + 1; + config.cpu.target_weight_ratio = rentbw_frac / 5 + 1; + }))); + BOOST_REQUIRE_EQUAL( // + "", // + t.configbw(t.make_default_config([&](auto& config) { + config.net.current_weight_ratio = rentbw_frac / 4; + config.net.target_weight_ratio = rentbw_frac / 4; + config.cpu.current_weight_ratio = rentbw_frac / 5; + config.cpu.target_weight_ratio = rentbw_frac / 5; + }))); } // net:30%, cpu:40%, then net:5%, cpu:10% From 21e0d9a08014c0f3a7de30614cea8e689c7e0080 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Wed, 11 Dec 2019 13:04:55 -0500 Subject: [PATCH 25/78] Missing action wrapper --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 8a2859df1..6436b7cba 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1292,6 +1292,7 @@ namespace eosiosystem { using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; using configcpu_action = eosio::action_wrapper<"configrentbw"_n, &system_contract::configrentbw>; + using rentbwexec_action = eosio::action_wrapper<"rentbwexec"_n, &system_contract::rentbwexec>; using rentbw_action = eosio::action_wrapper<"rentbw"_n, &system_contract::rentbw>; private: From 70e6c558d4bc8772f6207ef20139ab4731737975 Mon Sep 17 00:00:00 2001 From: Todd Fleming Date: Fri, 13 Dec 2019 10:41:02 -0500 Subject: [PATCH 26/78] Adjust min_rent_price description --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 6436b7cba..a0e58f8e9 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -502,8 +502,8 @@ namespace eosiosystem { rentbw_config_resource cpu; // CPU market configuration uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the // existing setting. - asset min_rent_price; // Rents below this amount are rejected. This needs to be large enough to cover - // RAM costs. Set this to 0 to preserve the existing setting. + asset min_rent_price; // Rents below this amount are rejected. Set this to 0 to preserve the + // existing setting. }; struct rentbw_state_resource { From 21a78feaef26cdfd59407f0b402c57c1e523e7e3 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 20:55:31 -0500 Subject: [PATCH 27/78] minor changes to rentbw system --- .../include/eosio.system/eosio.system.hpp | 13 +++--- contracts/eosio.system/src/rentbw.cpp | 44 ++++++++++++++----- contracts/eosio.system/src/rex.cpp | 1 + 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index a0e58f8e9..7ce3bb13f 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -484,15 +484,16 @@ namespace eosiosystem { // total rented by REX at the time the rentbw market is first activated. Set // this to 0 to preserve the existing setting; this avoids sudden price jumps. // For new chains which don't need to phase out staking and REX, 10^12 is - // probably a good value. + // probably a good value. time_point_sec target_timestamp; // Stop automatic weight_ratio shrinkage at this time. Once this // time hits, weight_ratio will be target_weight_ratio. Ignored if // current_weight_ratio == target_weight_ratio. Set this to 0 to preserve the // existing setting. double exponent; // Exponent of resource price curve. Must be >= 1. Set this to 0 to preserve the // existing setting. - uint32_t decay_secs; // Number of seconds for adjusted resource utilization to decay to instantaneous - // utilization within exp(-1). Set this to 0 to preserve the existing setting. + uint32_t decay_secs; // Number of seconds for the gap between adjusted resource utilization and + // instantaneous utilization to shrink by 63%. Set this to 0 to preserve the + // existing setting. asset target_price; // Fee needed to rent the entire resource market weight. Set this to 0 to // preserve the existing setting. }; @@ -526,8 +527,8 @@ namespace eosiosystem { asset target_price = {}; // Fee needed to rent the entire resource market weight. int64_t utilization = 0; // Instantaneous resource utilization. This is the current // amount sold. utilization <= weight. - int64_t adjusted_utilization = 0; // Adjusted resource utilization. This >= utilization. It - // grows instantly but decays exponentially. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This is >= utilization and + // <= weight. It grows instantly but decays exponentially. time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; @@ -1233,7 +1234,7 @@ namespace eosiosystem { /** * Rent NET and CPU - * + * * @param payer - the resource buyer * @param receiver - the resource receiver * @param days - number of days of resource availability. Must match market configuration. diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 4476b5ba2..4b2af9db1 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -1,9 +1,18 @@ #include -#include +#include +#include +#include namespace eosiosystem { void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available); + +/** + * @pre now >= res.utilization_timestamp + * @post res.utilization <= new res.adjusted_utilization + * @post if res.utilization < old res.adjusted_utilization, then new res.adjusted_utilization <= old res.adjusted_utilization + * @post if res.utilization >= old res.adjusted_utilization, then new res.adjusted_utilization == res.utilization + */ void update_utilization(time_point_sec now, rentbw_state_resource& res); void system_contract::adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, @@ -79,26 +88,30 @@ void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbo } void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available) { - if (now >= res.target_timestamp) + if (now >= res.target_timestamp) { res.weight_ratio = res.target_weight_ratio; - else + } else { res.weight_ratio = res.initial_weight_ratio + // int128_t(res.target_weight_ratio - res.initial_weight_ratio) * (now.utc_seconds - res.initial_timestamp.utc_seconds) / (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); - int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_frac) / res.weight_ratio - res.assumed_stake_weight; + } + int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_frac) / res.weight_ratio - res.assumed_stake_weight; delta_available += new_weight - res.weight; res.weight = new_weight; } void update_utilization(time_point_sec now, rentbw_state_resource& res) { - if (res.utilization >= res.adjusted_utilization) + if (now <= res.utilization_timestamp) return; + + if (res.utilization >= res.adjusted_utilization) { res.adjusted_utilization = res.utilization; - else - res.adjusted_utilization = // - res.utilization + - (res.adjusted_utilization - res.utilization) * - exp(-double(now.utc_seconds - res.utilization_timestamp.utc_seconds) / double(res.decay_secs)); + } else { + int64_t diff = res.adjusted_utilization - res.utilization; + int64_t delta = diff * std::exp(-double(now.utc_seconds - res.utilization_timestamp.utc_seconds) / double(res.decay_secs)); + delta = std::clamp( delta, 0ll, diff); + res.adjusted_utilization = res.utilization + delta; + } res.utilization_timestamp = now; } @@ -109,11 +122,18 @@ void system_contract::configrentbw(rentbw_config& args) { rentbw_state_singleton state_sing{ get_self(), 0 }; auto state = state_sing.get_or_default(); + eosio::check(eosio::is_account(reserv_account), "eosio.reserv account must first be created"); + int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; if (state_sing.exists()) { + update_utilization(now, state.net); + update_utilization(now, state.cpu); update_weight(now, state.net, net_delta_available); update_weight(now, state.cpu, cpu_delta_available); + } else { + state.net.utilization_timestamp = now; + state.cpu.utilization_timestamp = now; } auto update = [&](auto& state, auto& args) { @@ -183,13 +203,15 @@ void system_contract::configrentbw(rentbw_config& args) { update_weight(now, state.cpu, cpu_delta_available); eosio::check(state.net.weight >= state.net.utilization, "weight can't shrink below utilization"); eosio::check(state.cpu.weight >= state.cpu.utilization, "weight can't shrink below utilization"); + state.net.adjusted_utilization = std::min(state.net.adjusted_utilization, state.net.weight); + state.cpu.adjusted_utilization = std::min(state.cpu.adjusted_utilization, state.cpu.weight); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); } // system_contract::configrentbw int64_t calc_rentbw_price(const rentbw_state_resource& state, double utilization) { - return ceil(state.target_price.amount * pow(utilization / state.weight, state.exponent)); + return std::ceil(state.target_price.amount * std::pow(utilization / state.weight, state.exponent)); } void system_contract::rentbwexec(const name& user, uint16_t max) { diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index bcc8868db..dee9c0ab8 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -916,6 +916,7 @@ namespace eosiosystem { * * @param from - account from which asset is transfered to REX pool * @param amount - amount of tokens to be transfered + * @param required - if true, asserts when the system is not configured to channel fees into REX */ void system_contract::channel_to_rex( const name& from, const asset& amount, bool required ) { From a78cccd6d8b89980c6b018397930e7f93fe668ca Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 21:49:53 -0500 Subject: [PATCH 28/78] move comment (with the rentbw addition) to its proper place --- .../include/eosio.system/eosio.system.hpp | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 7ce3bb13f..50fb3f2e1 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -80,18 +80,6 @@ namespace eosiosystem { static constexpr int64_t default_inflation_pay_factor = 50000; // producers pay share = 10000 / 50000 = 20% of the inflation static constexpr int64_t default_votepay_factor = 40000; // per-block pay share = 10000 / 40000 = 25% of the producer pay - /** - * 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. - * - Producers 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 (REX) allows token holders to lend their tokens, - * and users to rent CPU and Network resources in return for a market-determined fee. - * - A resource market separate from REX: `rentbw` - */ - // 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 @@ -346,8 +334,8 @@ namespace eosiosystem { // - `version` defaulted to zero, // - `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, + // - `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, // - `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 { @@ -371,7 +359,7 @@ namespace eosiosystem { // `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 + // - `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; @@ -563,7 +551,15 @@ namespace eosiosystem { > rentbw_order_table; /** - * The EOSIO system contract. The EOSIO system contract governs ram market, voters, producers, global state. + * 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. + * - Producers 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 (REX) allows token holders to lend their tokens, + * and users to rent CPU and Network resources in return for a market-determined fee. + * - A resource market separate from REX: `rentbw`. */ class [[eosio::contract("eosio.system")]] system_contract : public native { From fed41410e824f4df0efbec9f88f8eade61502285 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 22:14:36 -0500 Subject: [PATCH 29/78] also change description of decay_secs in rentbw_state_resource to reflect the change in rentbw_config_resource --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 50fb3f2e1..5ab49de49 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -510,8 +510,8 @@ namespace eosiosystem { time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this // time hits, weight_ratio will be target_weight_ratio. double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs = 0; // Number of seconds for adjusted resource utilization to - // decay to instantaneous utilization within exp(-1). + uint32_t decay_secs; = 0; // Number of seconds for the gap between adjusted resource + // utilization and instantaneous utilization to shrink by 63%. asset target_price = {}; // Fee needed to rent the entire resource market weight. int64_t utilization = 0; // Instantaneous resource utilization. This is the current // amount sold. utilization <= weight. From 614579b126fe6743bcf087b5fa934f3de6cf5e6a Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 22:18:54 -0500 Subject: [PATCH 30/78] fix typo in previous commit --- 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 5ab49de49..4ff4bc1da 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -510,7 +510,7 @@ namespace eosiosystem { time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this // time hits, weight_ratio will be target_weight_ratio. double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs; = 0; // Number of seconds for the gap between adjusted resource + uint32_t decay_secs = 0; // Number of seconds for the gap between adjusted resource // utilization and instantaneous utilization to shrink by 63%. asset target_price = {}; // Fee needed to rent the entire resource market weight. int64_t utilization = 0; // Instantaneous resource utilization. This is the current From 929a53a86ea56a16f78f6d2591bcea45da36a60f Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 14:46:12 -0500 Subject: [PATCH 31/78] replace calc_rentbw_price with calc_rentbw_fee --- contracts/eosio.system/src/rentbw.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 4b2af9db1..f75118af8 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -210,8 +210,11 @@ void system_contract::configrentbw(rentbw_config& args) { state_sing.set(state, get_self()); } // system_contract::configrentbw -int64_t calc_rentbw_price(const rentbw_state_resource& state, double utilization) { - return std::ceil(state.target_price.amount * std::pow(utilization / state.weight, state.exponent)); +int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_increase) { + double start_utilization = state.adjusted_utilization; + double end_utilization = state.adjusted_utilization + utilization_increase; + return std::ceil(state.target_price.amount * std::pow(end_utilization / state.weight, state.exponent)) + - std::ceil(state.target_price.amount * std::pow(start_utilization / state.weight, state.exponent)); } void system_contract::rentbwexec(const name& user, uint16_t max) { @@ -258,8 +261,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d amount = int128_t(frac) * state.weight / rentbw_frac; eosio::check(state.weight, "market doesn't have resources available"); eosio::check(state.utilization + amount <= state.weight, "market doesn't have enough resources available"); - int64_t f = calc_rentbw_price(state, state.adjusted_utilization + amount) - - calc_rentbw_price(state, state.adjusted_utilization); + int64_t f = calc_rentbw_fee(state, amount); eosio::check(f > 0, "calculated fee is below minimum; try renting more"); fee.amount += f; state.utilization += amount; From 8a5620631fa96725f8ce65e625944ffb072c1d37 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 14:51:29 -0500 Subject: [PATCH 32/78] prefer rounding in a way that ensures fee calculation does not give advantage to very small rentals under particular situations (but still under the condition of utilization >= adjusted_utilization) Also add calculated fee to the error message when it exceeds max_payment. --- contracts/eosio.system/src/rentbw.cpp | 13 ++++++++++--- tests/eosio.rentbw_tests.cpp | 14 +++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index f75118af8..cb94c98de 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -213,8 +213,11 @@ void system_contract::configrentbw(rentbw_config& args) { int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_increase) { double start_utilization = state.adjusted_utilization; double end_utilization = state.adjusted_utilization + utilization_increase; - return std::ceil(state.target_price.amount * std::pow(end_utilization / state.weight, state.exponent)) - - std::ceil(state.target_price.amount * std::pow(start_utilization / state.weight, state.exponent)); + + double fee = state.target_price.amount * std::pow(end_utilization / state.weight, state.exponent) - + state.target_price.amount * std::pow(start_utilization / state.weight, state.exponent); + + return std::ceil(fee); } void system_contract::rentbwexec(const name& user, uint16_t max) { @@ -271,7 +274,11 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d int64_t cpu_amount = 0; process(net_frac, net_amount, state.net); process(cpu_frac, cpu_amount, state.cpu); - eosio::check(fee <= max_payment, "calculated fee exceeds max_payment"); + if (fee > max_payment) { + std::string error_msg = "max_payment is less than calculated fee: "; + error_msg += fee.to_string(); + eosio::check(false, error_msg); + } eosio::check(fee >= state.min_rent_price, "calculated fee is below minimum; try renting more"); orders.emplace(payer, [&](auto& order) { diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 4306ce383..b05120a98 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -515,7 +515,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac + 1, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("calculated fee exceeds max_payment"), // + t.wasm_assert_msg("max_payment is less than calculated fee: 3000000.0000 TST"), // t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("can't channel fees to rex"), // t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, @@ -573,9 +573,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.35 ^ 2) * 1000000.0000 - 90000.0000 = 32500.0000 // (.5 ^ 3) * 2000000.0000 - 128000.0000 = 122000.0000 // total = 154500.0000 - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("154499.9999")); + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("154500.0000")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .05, rentbw_frac * .10, - asset::from_string("154499.9999 TST"), net_weight * .05, cpu_weight * .10); + asset::from_string("154500.0000 TST"), net_weight * .05, cpu_weight * .10); } { @@ -650,9 +650,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // [((e^-2 + 1.0) ^ 2) - ((e^-2) ^ 2) ] * 1000000.0000 = 1270670.5664 // [((e^-2 + 1.0) ^ 3) - ((e^-2) ^ 3) ] * 2000000.0000 = 2921905.5327 // total = 4192576.0991 - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("4192561.0244")); + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("4192561.0246")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, - asset::from_string("4192561.0244 TST"), net_weight, cpu_weight); + asset::from_string("4192561.0246 TST"), net_weight, cpu_weight); } { @@ -673,9 +673,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.3 ^ 2) * 1000000.0000 - 10000.0000 = 80000.0000 // (.4 ^ 3) * 2000000.0000 - 16000.0000 = 112000.0000 // total = 192000.0000 - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("191999.9999")); + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("192000.0001")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .2, rentbw_frac * .2, - asset::from_string("191999.9999 TST"), net_weight * .2, cpu_weight * .2); + asset::from_string("192000.0001 TST"), net_weight * .2, cpu_weight * .2); // Start decay t.produce_block(fc::days(15) - fc::milliseconds(1000)); From b728e01965e9e6b2e3307a0e5b10b1b09778652c Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 16:24:37 -0500 Subject: [PATCH 33/78] fix name of configrentbw action wrapper type --- 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 4ff4bc1da..764174a1f 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -1288,7 +1288,7 @@ namespace eosiosystem { using setalimits_action = eosio::action_wrapper<"setalimits"_n, &system_contract::setalimits>; using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; - using configcpu_action = eosio::action_wrapper<"configrentbw"_n, &system_contract::configrentbw>; + using configrentbw_action = eosio::action_wrapper<"configrentbw"_n, &system_contract::configrentbw>; using rentbwexec_action = eosio::action_wrapper<"rentbwexec"_n, &system_contract::rentbwexec>; using rentbw_action = eosio::action_wrapper<"rentbw"_n, &system_contract::rentbw>; From 826a6cd6fc2a4b7cf8256ea44a79061021d171e1 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 17:35:20 -0500 Subject: [PATCH 34/78] add default values for rent_days, decay_secs, and exponent --- .../include/eosio.system/eosio.system.hpp | 64 +++++++++++-------- tests/eosio.rentbw_tests.cpp | 12 ++-- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 764174a1f..89e428a83 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -40,7 +40,7 @@ namespace eosiosystem { using eosio::time_point_sec; using eosio::unsigned_int; - inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 + inline constexpr int64_t rentbw_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 template static inline auto has_field( F flags, E field ) @@ -496,36 +496,48 @@ namespace eosiosystem { }; struct rentbw_state_resource { + static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a + // tiny amount of resources increases linearly + // with utilization. + static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a + // single loan, then, assuming no further renting, + // 1 day after it expires the adjusted utilization + // will be at approximately 37% and after 3 days the + // adjusted utilization will be at least than 5%. + + uint8_t version = 0; - int64_t weight = 0; // resource market weight. calculated; varies over time. - // 1 represents the same amount of resources as 1 - // satoshi of SYS staked. - int64_t weight_ratio = 0; // resource market weight ratio: - // assumed_stake_weight / (assumed_stake_weight + weight). - // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. - int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. - int64_t initial_weight_ratio = rentbw_frac; // Initial weight_ratio used for linear shrinkage. - int64_t target_weight_ratio = rentbw_frac / 100; // Linearly shrink the weight_ratio to this amount. - time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started - time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this - // time hits, weight_ratio will be target_weight_ratio. - double exponent = 0; // Exponent of resource price curve. - uint32_t decay_secs = 0; // Number of seconds for the gap between adjusted resource - // utilization and instantaneous utilization to shrink by 63%. - asset target_price = {}; // Fee needed to rent the entire resource market weight. - int64_t utilization = 0; // Instantaneous resource utilization. This is the current - // amount sold. utilization <= weight. - int64_t adjusted_utilization = 0; // Adjusted resource utilization. This is >= utilization and - // <= weight. It grows instantly but decays exponentially. - time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated + int64_t weight = 0; // resource market weight. calculated; varies over time. + // 1 represents the same amount of resources as 1 + // satoshi of SYS staked. + int64_t weight_ratio = 0; // resource market weight ratio: + // assumed_stake_weight / (assumed_stake_weight + weight). + // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. + int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. + int64_t initial_weight_ratio = rentbw_frac; // Initial weight_ratio used for linear shrinkage. + int64_t target_weight_ratio = rentbw_frac / 100; // Linearly shrink the weight_ratio to this amount. + time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started + time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. + double exponent = default_exponent; // Exponent of resource price curve. + uint32_t decay_secs = default_decay_secs; // Number of seconds for the gap between adjusted resource + // utilization and instantaneous utilization to shrink by 63%. + asset target_price = {}; // Fee needed to rent the entire resource market weight. + int64_t utilization = 0; // Instantaneous resource utilization. This is the current + // amount sold. utilization <= weight. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This is >= utilization and + // <= weight. It grows instantly but decays exponentially. + time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { + static constexpr uint32_t default_rent_days = 30 * seconds_per_day; // 30 day resource rentals + uint8_t version = 0; - rentbw_state_resource net = {}; // NET market state - rentbw_state_resource cpu = {}; // CPU market state - uint32_t rent_days = 0; // `rentbw` `days` argument must match this. - asset min_rent_price = {}; // Rents below this amount are rejected + rentbw_state_resource net = {}; // NET market state + rentbw_state_resource cpu = {}; // CPU market state + uint32_t rent_days = default_rent_days; // `rentbw` `days` argument must match this. + asset min_rent_price = {}; // Rents below this amount are rejected uint64_t primary_key()const { return 0; } }; diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index b05120a98..d04c8102c 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -226,8 +226,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { push_action(N(alice1111111), N(configrentbw), mvo()("args", make_config()))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("rentbw hasn't been initialized"), rentbwexec(N(alice1111111), 10)); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), - configbw(make_config([&](auto& c) { c.rent_days = 0; }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), + // configbw(make_config([&](auto& c) { c.rent_days = 0; }))); // needed only if rent_days does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("1000000.000 TST"); }))); @@ -255,8 +255,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), - configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + // configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); // needed only if decay_secs does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("1000000.000 TST"); }))); @@ -284,8 +284,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), - configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + // configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); // needed only if decay_secs does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("1000000.000 TST"); }))); From 0194167262a5039a77b2271b7a7b81639e2929bc Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 18:47:03 -0500 Subject: [PATCH 35/78] add default values for min_rent_price and target_price as well --- .../include/eosio.system/eosio.system.hpp | 23 +++++++++++-------- contracts/eosio.system/src/rentbw.cpp | 16 +++++++++---- tests/eosio.rentbw_tests.cpp | 12 +++++----- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 89e428a83..7e6467189 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -496,15 +496,16 @@ namespace eosiosystem { }; struct rentbw_state_resource { - static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a - // tiny amount of resources increases linearly - // with utilization. - static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a - // single loan, then, assuming no further renting, - // 1 day after it expires the adjusted utilization - // will be at approximately 37% and after 3 days the - // adjusted utilization will be at least than 5%. - + static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a + // tiny amount of resources increases linearly + // with utilization. + static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a + // single loan, then, assuming no further renting, + // 1 day after it expires the adjusted utilization + // will be at approximately 37% and after 3 days the + // adjusted utilization will be at least than 5%. + static constexpr int64_t default_target_price = 100'000'000'0000ll; // 100000000.0000 SYS + // (assuming get_core_symbol() == symbol("SYS", 4)); uint8_t version = 0; int64_t weight = 0; // resource market weight. calculated; varies over time. @@ -531,7 +532,9 @@ namespace eosiosystem { }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { - static constexpr uint32_t default_rent_days = 30 * seconds_per_day; // 30 day resource rentals + static constexpr uint32_t default_rent_days = 30 * seconds_per_day; // 30 day resource rentals + static constexpr int64_t default_min_rent_price = 100ll; // 0.0100 SYS + // (assuming get_core_symbol() == symbol("SYS", 4)) uint8_t version = 0; rentbw_state_resource net = {}; // NET market state diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index cb94c98de..02d70fc11 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -153,8 +153,12 @@ void system_contract::configrentbw(rentbw_config& args) { args.exponent = state.exponent; if (!args.decay_secs) args.decay_secs = state.decay_secs; - if (!args.target_price.amount && state.target_price.amount) - args.target_price = state.target_price; + if (!args.target_price.amount) { + if (state.target_price.amount) + args.target_price = state.target_price; + else + args.target_price.amount = rentbw_state_resource::default_target_price; + } if (args.current_weight_ratio == args.target_weight_ratio) args.target_timestamp = now; @@ -186,8 +190,12 @@ void system_contract::configrentbw(rentbw_config& args) { if (!args.rent_days) args.rent_days = state.rent_days; - if (!args.min_rent_price.amount && state.min_rent_price.amount) - args.min_rent_price = state.min_rent_price; + if (!args.min_rent_price.amount) { + if (state.min_rent_price.amount) + args.min_rent_price = state.min_rent_price; + else + args.min_rent_price.amount = rentbw_state::default_min_rent_price; + } eosio::check(args.rent_days > 0, "rent_days must be > 0"); eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index d04c8102c..8d982b4e3 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -231,8 +231,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("1000000.000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), - configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), + // configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); // needed only if min_rent_price does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("-1.0000 TST"); }))); @@ -260,8 +260,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("1000000.000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + // configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); // needed only if target_price does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("-1.0000 TST"); }))); @@ -289,8 +289,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("1000000.000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); + //BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + // configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); // needed only if target_price does not have default BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); } // config_tests From abb52c323a3e4bc646477f50acc9a4c5d6247ec9 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 18:52:33 -0500 Subject: [PATCH 36/78] fix wrong default value for rent_days --- contracts/eosio.system/include/eosio.system/eosio.system.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 7e6467189..c07aa274a 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -532,9 +532,8 @@ namespace eosiosystem { }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { - static constexpr uint32_t default_rent_days = 30 * seconds_per_day; // 30 day resource rentals - static constexpr int64_t default_min_rent_price = 100ll; // 0.0100 SYS - // (assuming get_core_symbol() == symbol("SYS", 4)) + static constexpr uint32_t default_rent_days = 30; // 30 day resource rentals + static constexpr int64_t default_min_rent_price = 100ll; // 0.0100 SYS (assuming get_core_symbol() == symbol("SYS", 4)) uint8_t version = 0; rentbw_state_resource net = {}; // NET market state From 8328052ada7db9c7f7dd137e0bdb8645b14f5306 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 19:46:33 -0500 Subject: [PATCH 37/78] fix comment --- .../eosio.system/include/eosio.system/eosio.system.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index c07aa274a..81f5c0c76 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -502,10 +502,10 @@ namespace eosiosystem { static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a // single loan, then, assuming no further renting, // 1 day after it expires the adjusted utilization - // will be at approximately 37% and after 3 days the - // adjusted utilization will be at least than 5%. + // will be at approximately 37% and after 3 days + // the adjusted utilization will be less than 5%. static constexpr int64_t default_target_price = 100'000'000'0000ll; // 100000000.0000 SYS - // (assuming get_core_symbol() == symbol("SYS", 4)); + // (assuming get_core_symbol() == symbol("SYS", 4)) uint8_t version = 0; int64_t weight = 0; // resource market weight. calculated; varies over time. From ae8230d980a7ad9f1fc8a48c186531190f1a9dde Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 19:58:01 -0500 Subject: [PATCH 38/78] fix comment description of some configuration options --- .../include/eosio.system/eosio.system.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 81f5c0c76..bb5d79031 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -478,21 +478,21 @@ namespace eosiosystem { // current_weight_ratio == target_weight_ratio. Set this to 0 to preserve the // existing setting. double exponent; // Exponent of resource price curve. Must be >= 1. Set this to 0 to preserve the - // existing setting. + // existing setting or use the default. uint32_t decay_secs; // Number of seconds for the gap between adjusted resource utilization and // instantaneous utilization to shrink by 63%. Set this to 0 to preserve the - // existing setting. - asset target_price; // Fee needed to rent the entire resource market weight. Set this to 0 to - // preserve the existing setting. + // existing setting or use the default. + asset target_price; // Fee needed to rent the entire resource market weight. Set the amount of this + // asset to 0 to preserve the existing setting or use the default. }; struct rentbw_config { rentbw_config_resource net; // NET market configuration rentbw_config_resource cpu; // CPU market configuration uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the - // existing setting. - asset min_rent_price; // Rents below this amount are rejected. Set this to 0 to preserve the - // existing setting. + // existing setting or use the default. + asset min_rent_price; // Rents below this amount are rejected. Set the amount of this asset to 0 to + // preserve the existing setting or use the default. }; struct rentbw_state_resource { From 92362d8b4dc8b7ea15a52b3eef0e9bfb9fb8eff3 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 18 Dec 2019 20:31:09 -0500 Subject: [PATCH 39/78] remove defaults for min_rent_price and target_price since values that are resonable dependent heavily on the attributes of the core token --- .../include/eosio.system/eosio.system.hpp | 7 ++----- contracts/eosio.system/src/rentbw.cpp | 16 ++++------------ tests/eosio.rentbw_tests.cpp | 14 +++++++------- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index bb5d79031..9d5ded4b0 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -483,7 +483,7 @@ namespace eosiosystem { // instantaneous utilization to shrink by 63%. Set this to 0 to preserve the // existing setting or use the default. asset target_price; // Fee needed to rent the entire resource market weight. Set the amount of this - // asset to 0 to preserve the existing setting or use the default. + // asset to 0 to preserve the existing setting. }; struct rentbw_config { @@ -492,7 +492,7 @@ namespace eosiosystem { uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the // existing setting or use the default. asset min_rent_price; // Rents below this amount are rejected. Set the amount of this asset to 0 to - // preserve the existing setting or use the default. + // preserve the existing setting. }; struct rentbw_state_resource { @@ -504,8 +504,6 @@ namespace eosiosystem { // 1 day after it expires the adjusted utilization // will be at approximately 37% and after 3 days // the adjusted utilization will be less than 5%. - static constexpr int64_t default_target_price = 100'000'000'0000ll; // 100000000.0000 SYS - // (assuming get_core_symbol() == symbol("SYS", 4)) uint8_t version = 0; int64_t weight = 0; // resource market weight. calculated; varies over time. @@ -533,7 +531,6 @@ namespace eosiosystem { struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { static constexpr uint32_t default_rent_days = 30; // 30 day resource rentals - static constexpr int64_t default_min_rent_price = 100ll; // 0.0100 SYS (assuming get_core_symbol() == symbol("SYS", 4)) uint8_t version = 0; rentbw_state_resource net = {}; // NET market state diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 02d70fc11..cb94c98de 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -153,12 +153,8 @@ void system_contract::configrentbw(rentbw_config& args) { args.exponent = state.exponent; if (!args.decay_secs) args.decay_secs = state.decay_secs; - if (!args.target_price.amount) { - if (state.target_price.amount) - args.target_price = state.target_price; - else - args.target_price.amount = rentbw_state_resource::default_target_price; - } + if (!args.target_price.amount && state.target_price.amount) + args.target_price = state.target_price; if (args.current_weight_ratio == args.target_weight_ratio) args.target_timestamp = now; @@ -190,12 +186,8 @@ void system_contract::configrentbw(rentbw_config& args) { if (!args.rent_days) args.rent_days = state.rent_days; - if (!args.min_rent_price.amount) { - if (state.min_rent_price.amount) - args.min_rent_price = state.min_rent_price; - else - args.min_rent_price.amount = rentbw_state::default_min_rent_price; - } + if (!args.min_rent_price.amount && state.min_rent_price.amount) + args.min_rent_price = state.min_rent_price; eosio::check(args.rent_days > 0, "rent_days must be > 0"); eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 8d982b4e3..9ca41b564 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -12,7 +12,7 @@ #include "eosio.system_tester.hpp" -inline constexpr int64_t rentbw_frac = 1000000000000000ll; // 1.0 = 10^15 +inline constexpr int64_t rentbw_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 inline constexpr int64_t stake_weight = 100'000'000'0000ll; // 10^12 struct rentbw_config_resource { @@ -231,8 +231,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("1000000.000 TST"); }))); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), - // configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); // needed only if min_rent_price does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), + configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("-1.0000 TST"); }))); @@ -260,8 +260,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("1000000.000 TST"); }))); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - // configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); // needed only if target_price does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("-1.0000 TST"); }))); @@ -289,8 +289,8 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("1000000.000 TST"); }))); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - // configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); // needed only if target_price does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), + configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); } // config_tests From 5fc0dac07ec150248b8e2c964fbbbe0382c4fb51 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Dec 2019 13:29:51 -0500 Subject: [PATCH 40/78] modify fee calculation to not give advantage to very small rentals even under the scenario of utilization <= adjusted_utilization --- contracts/eosio.system/src/rentbw.cpp | 49 ++++++++++++++++++++++++--- tests/eosio.rentbw_tests.cpp | 20 +++++------ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index cb94c98de..cacd5e53c 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -210,12 +210,53 @@ void system_contract::configrentbw(rentbw_config& args) { state_sing.set(state, get_self()); } // system_contract::configrentbw +/** + * @pre 0 < state.target_price.amount + * @pre 1.0 <= state.exponent + * @pre 0 <= state.utilization <= state.adjusted_utilization <= state.weight + * @pre 0 <= utilization_increase <= (state.weight - state.utilization) + */ int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_increase) { - double start_utilization = state.adjusted_utilization; - double end_utilization = state.adjusted_utilization + utilization_increase; + if( utilization_increase <= 0 ) return 0; + + // Let p(u) = price as a function of the utilization fraction u which is defined for u in [0.0, 1.0]. + // Let f(u) = integral of the price function p(x) from x = 0.0 to x = u, again defined for u in [0.0, 1.0]. + + // Returns f(double(end_utilization)/state.weight) - f(double(start_utilization)/state.weight) which is equivalent to + // the integral of p(x) from x = double(start_utilization)/state.weight to x = double(end_utilization)/state.weight. + // @pre 0 <= start_utilization <= end_utilization <= state.weight + auto price_integral_delta = [&state](int64_t start_utilization, int64_t end_utilization) -> double { + return state.target_price.amount * std::pow(double(end_utilization) / state.weight, state.exponent) - + state.target_price.amount * std::pow(double(start_utilization) / state.weight, state.exponent); + }; + + // Returns p(double(utilization)/state.weight). + // @pre 0 <= utilization <= state.weight + auto price_function = [&state](int64_t utilization) -> double { + // state.exponent >= 1.0, therefore the exponent passed into std::pow is >= 0.0. + // Since the exponent passed into std::pow could be 0.0 and simultaneously so could double(utilization)/state.weight, + // the safest thing to do is handle that as a special case explicitly rather than relying on std::pow to return 1.0 + // instead of triggering a domain error. + double new_exponent = state.exponent - 1.0; + if (new_exponent <= 0.0) + return state.target_price.amount; + else + return state.exponent * state.target_price.amount * std::pow(double(utilization) / state.weight, new_exponent); + }; + + double fee = 0.0; + int64_t start_utilization = state.utilization; + int64_t end_utilization = start_utilization + utilization_increase; - double fee = state.target_price.amount * std::pow(end_utilization / state.weight, state.exponent) - - state.target_price.amount * std::pow(start_utilization / state.weight, state.exponent); + if (start_utilization < state.adjusted_utilization) { + fee += price_function(state.adjusted_utilization) * + std::min(utilization_increase, state.adjusted_utilization - start_utilization) / state.weight; + start_utilization = state.adjusted_utilization; + } + + if (start_utilization < end_utilization) { + fee += price_integral_delta(start_utilization, end_utilization); + } return std::ceil(fee); } diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 9ca41b564..23f3fb9a9 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -602,12 +602,12 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // immediate renewal: adjusted_utilization doesn't have time to fall // - // (2.0 ^ 2) * 1000000.0000 - 1000000.0000 = 3000000.0000 - // (2.0 ^ 3) * 2000000.0000 - 2000000.0000 = 14000000.0000 - // total = 17000000.0000 - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("17000000.0000")); + // 2 * (1.0 ^ 1) * 1000000.0000 = 2000000.0000 + // 3 * (1.0 ^ 2) * 2000000.0000 = 6000000.0000 + // total = 8000000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("8000000.0000")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, - asset::from_string("17000000.0000 TST"), 0, 0); + asset::from_string("8000000.0000 TST"), 0, 0); // No more available for 30 days BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // @@ -647,12 +647,12 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // 100% after 2 days of decay // - // [((e^-2 + 1.0) ^ 2) - ((e^-2) ^ 2) ] * 1000000.0000 = 1270670.5664 - // [((e^-2 + 1.0) ^ 3) - ((e^-2) ^ 3) ] * 2000000.0000 = 2921905.5327 - // total = 4192576.0991 - t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("4192561.0246")); + // [ [2 * ((e^-2) ^ 1)]*(e^-2 - 0.0) + ((1.0) ^ 2) - ((e^-2) ^ 2) ] * 1000000.0000 = 1018315.6389 + // [ [3 * ((e^-2) ^ 2)]*(e^-2 - 0.0) + ((1.0) ^ 3) - ((e^-2) ^ 3) ] * 2000000.0000 = 2009915.0087 + // total = 3028230.6476 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3028229.8795")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, - asset::from_string("4192561.0246 TST"), net_weight, cpu_weight); + asset::from_string("3028229.8795 TST"), net_weight, cpu_weight); } { From 49c6b09d8657d6d1b8cdc83a5e1077eff6c01615 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Dec 2019 13:37:21 -0500 Subject: [PATCH 41/78] rename min_rent_price to min_rent_fee --- .../include/eosio.system/eosio.system.hpp | 24 ++++++------ contracts/eosio.system/src/rentbw.cpp | 14 +++---- tests/eosio.rentbw_tests.cpp | 38 +++++++++---------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 9d5ded4b0..f61c746a3 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -487,12 +487,12 @@ namespace eosiosystem { }; struct rentbw_config { - rentbw_config_resource net; // NET market configuration - rentbw_config_resource cpu; // CPU market configuration - uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the - // existing setting or use the default. - asset min_rent_price; // Rents below this amount are rejected. Set the amount of this asset to 0 to - // preserve the existing setting. + rentbw_config_resource net; // NET market configuration + rentbw_config_resource cpu; // CPU market configuration + uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the + // existing setting or use the default. + asset min_rent_fee; // Rental fees below this amount are rejected. Set the amount of this asset to 0 + // to preserve the existing setting. }; struct rentbw_state_resource { @@ -530,13 +530,13 @@ namespace eosiosystem { }; struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { - static constexpr uint32_t default_rent_days = 30; // 30 day resource rentals + static constexpr uint32_t default_rent_days = 30; // 30 day resource rentals - uint8_t version = 0; - rentbw_state_resource net = {}; // NET market state - rentbw_state_resource cpu = {}; // CPU market state - uint32_t rent_days = default_rent_days; // `rentbw` `days` argument must match this. - asset min_rent_price = {}; // Rents below this amount are rejected + uint8_t version = 0; + rentbw_state_resource net = {}; // NET market state + rentbw_state_resource cpu = {}; // CPU market state + uint32_t rent_days = default_rent_days; // `rentbw` `days` argument must match this. + asset min_rent_fee = {}; // Rental fees below this amount are rejected uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index cacd5e53c..6add2ee77 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -186,15 +186,15 @@ void system_contract::configrentbw(rentbw_config& args) { if (!args.rent_days) args.rent_days = state.rent_days; - if (!args.min_rent_price.amount && state.min_rent_price.amount) - args.min_rent_price = state.min_rent_price; + if (!args.min_rent_fee.amount && state.min_rent_fee.amount) + args.min_rent_fee = state.min_rent_fee; eosio::check(args.rent_days > 0, "rent_days must be > 0"); - eosio::check(args.min_rent_price.symbol == core_symbol, "min_rent_price doesn't match core symbol"); - eosio::check(args.min_rent_price.amount > 0, "min_rent_price must be positive"); + eosio::check(args.min_rent_fee.symbol == core_symbol, "min_rent_fee doesn't match core symbol"); + eosio::check(args.min_rent_fee.amount > 0, "min_rent_fee must be positive"); - state.rent_days = args.rent_days; - state.min_rent_price = args.min_rent_price; + state.rent_days = args.rent_days; + state.min_rent_fee = args.min_rent_fee; update(state.net, args.net); update(state.cpu, args.cpu); @@ -320,7 +320,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d error_msg += fee.to_string(); eosio::check(false, error_msg); } - eosio::check(fee >= state.min_rent_price, "calculated fee is below minimum; try renting more"); + eosio::check(fee >= state.min_rent_fee, "calculated fee is below minimum; try renting more"); orders.emplace(payer, [&](auto& order) { order.id = orders.available_primary_key(); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 23f3fb9a9..d1d0f98cd 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -29,12 +29,12 @@ FC_REFLECT(rentbw_config_resource, (exponent)(decay_secs)(target_price)) struct rentbw_config { - rentbw_config_resource net = {}; - rentbw_config_resource cpu = {}; - uint32_t rent_days = {}; - asset min_rent_price = asset{}; + rentbw_config_resource net = {}; + rentbw_config_resource cpu = {}; + uint32_t rent_days = {}; + asset min_rent_fee = asset{}; }; -FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_price)) +FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_fee)) struct rentbw_state_resource { uint8_t version; @@ -62,9 +62,9 @@ struct rentbw_state { rentbw_state_resource net; rentbw_state_resource cpu; uint32_t rent_days; - asset min_rent_price; + asset min_rent_fee; }; -FC_REFLECT(rentbw_state, (version)(net)(cpu)(rent_days)(min_rent_price)) +FC_REFLECT(rentbw_state, (version)(net)(cpu)(rent_days)(min_rent_fee)) using namespace eosio_system; @@ -109,8 +109,8 @@ struct rentbw_tester : eosio_system_tester { config.cpu.decay_secs = fc::days(1).to_seconds(); config.cpu.target_price = asset::from_string("1000000.0000 TST"); - config.rent_days = 30; - config.min_rent_price = asset::from_string("1.0000 TST"); + config.rent_days = 30; + config.min_rent_fee = asset::from_string("1.0000 TST"); f(config); return config; @@ -228,13 +228,13 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { //BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), // configbw(make_config([&](auto& c) { c.rent_days = 0; }))); // needed only if rent_days does not have default - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price doesn't match core symbol"), configbw(make_config([&](auto& c) { - c.min_rent_price = asset::from_string("1000000.000 TST"); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.min_rent_fee = asset::from_string("1000000.000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), - configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("0.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_price must be positive"), - configbw(make_config([&](auto& c) { c.min_rent_price = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), + configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), + configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("-1.0000 TST"); }))); // net assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), @@ -445,8 +445,8 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { config.cpu.exponent = 1; config.cpu.target_price = asset::from_string("1000000.0000 TST"); - config.rent_days = 30; - config.min_rent_price = asset::from_string("1.0000 TST"); + config.rent_days = 30; + config.min_rent_fee = asset::from_string("1.0000 TST"); }))); BOOST_REQUIRE_EQUAL( @@ -477,8 +477,8 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { config.cpu.exponent = 3; config.cpu.target_price = asset::from_string("2000000.0000 TST"); - config.rent_days = 30; - config.min_rent_price = asset::from_string("1.0000 TST"); + config.rent_days = 30; + config.min_rent_fee = asset::from_string("1.0000 TST"); }))); if (rex) From 58fb95fff6827749501f51e81da4344c2e697383 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Dec 2019 17:25:54 -0500 Subject: [PATCH 42/78] use optionals rather than 0 for config parameters to signal that it should preserve the existing value (or use default when appropriate) --- .../include/eosio.system/eosio.system.hpp | 59 +++++---- contracts/eosio.system/src/rentbw.cpp | 121 +++++++++++------- tests/eosio.rentbw_tests.cpp | 74 ++++++++--- 3 files changed, 164 insertions(+), 90 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index f61c746a3..b8abe590a 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -461,38 +461,45 @@ namespace eosiosystem { }; struct rentbw_config_resource { - int64_t current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. Set this - // to 0 to preserve the existing setting or use the default; this avoids sudden - // price jumps. For new chains which don't need to gradually phase out staking - // and REX, 0.01x (10^13) is a good value for both current_weight_ratio and - // target_weight_ratio. - int64_t target_weight_ratio; // Linearly shrink weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. Set this - // to 0 to preserve the existing setting or use the default. - int64_t assumed_stake_weight; // Assumed stake weight for ratio calculations. Use the sum of total staked and - // total rented by REX at the time the rentbw market is first activated. Set - // this to 0 to preserve the existing setting; this avoids sudden price jumps. - // For new chains which don't need to phase out staking and REX, 10^12 is - // probably a good value. - time_point_sec target_timestamp; // Stop automatic weight_ratio shrinkage at this time. Once this - // time hits, weight_ratio will be target_weight_ratio. Ignored if - // current_weight_ratio == target_weight_ratio. Set this to 0 to preserve the - // existing setting. - double exponent; // Exponent of resource price curve. Must be >= 1. Set this to 0 to preserve the - // existing setting or use the default. - uint32_t decay_secs; // Number of seconds for the gap between adjusted resource utilization and - // instantaneous utilization to shrink by 63%. Set this to 0 to preserve the - // existing setting or use the default. - asset target_price; // Fee needed to rent the entire resource market weight. Set the amount of this - // asset to 0 to preserve the existing setting. + std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. + // Do not specify to preserve the existing setting or use the default; + // this avoids sudden price jumps. For new chains which don't need + // to gradually phase out staking and REX, 0.01x (10^13) is a good + // value for both current_weight_ratio and target_weight_ratio. + std::optional target_weight_ratio; // Linearly shrink weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. + // Do not specify to preserve the existing setting or use the default. + std::optional assumed_stake_weight; // Assumed stake weight for ratio calculations. Use the sum of total + // staked and total rented by REX at the time the rentbw market + // is first activated. Do not specify to preserve the existing + // setting (no default exists); this avoids sudden price jumps. + // For new chains which don't need to phase out staking and REX, + // 10^12 is probably a good value. + std::optional target_timestamp; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. Ignored + // if current_weight_ratio == target_weight_ratio. Do not specify + // this to preserve the existing setting (no default exists). + std::optional exponent; // Exponent of resource price curve. Must be >= 1. Do not specify + // to preserve the existing setting or use the default. + std::optional decay_secs; // Number of seconds for the gap between adjusted resource + // utilization and instantaneous resource utilization to shrink + // by 63%. Do not specify to preserve the existing setting or + // use the default. + std::optional target_price; // Fee needed to rent the entire resource market weight. Do not + // specify to preserve the existing setting (no default exists). + + EOSLIB_SERIALIZE( rentbw_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) + (target_timestamp)(exponent)(decay_secs)(target_price) ) }; struct rentbw_config { rentbw_config_resource net; // NET market configuration rentbw_config_resource cpu; // CPU market configuration - uint32_t rent_days; // `rentbw` `days` argument must match this. Set this to 0 to preserve the + std::optional rent_days; // `rentbw` `days` argument must match this. Do not specify to preserve the // existing setting or use the default. - asset min_rent_fee; // Rental fees below this amount are rejected. Set the amount of this asset to 0 - // to preserve the existing setting. + std::optional min_rent_fee; // Rental fees below this amount are rejected. Do not specify to preserve the + // existing setting (no default exists). + + EOSLIB_SERIALIZE( rentbw_config, (net)(cpu)(rent_days)(min_rent_fee) ) }; struct rentbw_state_resource { diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 6add2ee77..98513d96b 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -136,65 +136,90 @@ void system_contract::configrentbw(rentbw_config& args) { state.cpu.utilization_timestamp = now; } + auto is_default_asset = []( const eosio::asset& a ) -> bool { + return a.amount == 0 && a.symbol == symbol{}; + }; + auto update = [&](auto& state, auto& args) { if (!args.current_weight_ratio) { - if (state.weight_ratio) - args.current_weight_ratio = state.weight_ratio; - else - args.current_weight_ratio = state.initial_weight_ratio; + if (state.weight_ratio) { + *args.current_weight_ratio = state.weight_ratio; + } else { + *args.current_weight_ratio = state.initial_weight_ratio; + } } - if (!args.target_weight_ratio) - args.target_weight_ratio = state.target_weight_ratio; - if (!args.assumed_stake_weight) - args.assumed_stake_weight = state.assumed_stake_weight; - if (!args.target_timestamp.utc_seconds) - args.target_timestamp = state.target_timestamp; - if (!args.exponent) - args.exponent = state.exponent; - if (!args.decay_secs) - args.decay_secs = state.decay_secs; - if (!args.target_price.amount && state.target_price.amount) - args.target_price = state.target_price; - - if (args.current_weight_ratio == args.target_weight_ratio) - args.target_timestamp = now; - else - eosio::check(args.target_timestamp > now, "target_timestamp must be in the future"); - eosio::check(args.current_weight_ratio > 0, "current_weight_ratio is too small"); - eosio::check(args.current_weight_ratio <= rentbw_frac, "current_weight_ratio is too large"); - eosio::check(args.target_weight_ratio > 0, "target_weight_ratio is too small"); - eosio::check(args.target_weight_ratio <= args.current_weight_ratio, "weight can't grow over time"); - eosio::check(args.assumed_stake_weight >= 1, + + if (!args.target_weight_ratio) { + *args.target_weight_ratio = state.target_weight_ratio; + } + + if (!args.assumed_stake_weight) { + eosio::check(state.assumed_stake_weight != 0, "assumed_stake_weight does not have a default value"); + *args.assumed_stake_weight = state.assumed_stake_weight; + } + + if (*args.current_weight_ratio == *args.target_weight_ratio) { + *args.target_timestamp = now; + } else { + if (!args.target_timestamp) { + eosio::check(state.target_timestamp.utc_seconds != 0, "target_timestamp does not have a default value"); + *args.target_timestamp = state.target_timestamp; + } + eosio::check(*args.target_timestamp > now, "target_timestamp must be in the future"); + } + + if (!args.exponent) { + *args.exponent = state.exponent; + } + + if (!args.decay_secs) { + *args.decay_secs = state.decay_secs; + } + + if (!args.target_price) { + eosio::check(!is_default_asset(state.target_price), "target_price does not have a default value"); + *args.target_price = state.target_price; + } + + eosio::check(*args.current_weight_ratio > 0, "current_weight_ratio is too small"); + eosio::check(*args.current_weight_ratio <= rentbw_frac, "current_weight_ratio is too large"); + eosio::check(*args.target_weight_ratio > 0, "target_weight_ratio is too small"); + eosio::check(*args.target_weight_ratio <= *args.current_weight_ratio, "weight can't grow over time"); + eosio::check(*args.assumed_stake_weight >= 1, "assumed_stake_weight must be at least 1; a much larger value is recommended"); - eosio::check(args.assumed_stake_weight * int128_t(rentbw_frac) / args.target_weight_ratio <= + eosio::check(*args.assumed_stake_weight * int128_t(rentbw_frac) / *args.target_weight_ratio <= std::numeric_limits::max(), "assumed_stake_weight/target_weight_ratio is too large"); - eosio::check(args.exponent >= 1, "exponent must be >= 1"); - eosio::check(args.decay_secs >= 1, "decay_secs must be >= 1"); - eosio::check(args.target_price.symbol == core_symbol, "target_price doesn't match core symbol"); - eosio::check(args.target_price.amount > 0, "target_price must be positive"); - - state.assumed_stake_weight = args.assumed_stake_weight; - state.initial_weight_ratio = args.current_weight_ratio; - state.target_weight_ratio = args.target_weight_ratio; + eosio::check(*args.exponent >= 1, "exponent must be >= 1"); + eosio::check(*args.decay_secs >= 1, "decay_secs must be >= 1"); + eosio::check(args.target_price->symbol == core_symbol, "target_price doesn't match core symbol"); + eosio::check(args.target_price->amount > 0, "target_price must be positive"); + + state.assumed_stake_weight = *args.assumed_stake_weight; + state.initial_weight_ratio = *args.current_weight_ratio; + state.target_weight_ratio = *args.target_weight_ratio; state.initial_timestamp = now; - state.target_timestamp = args.target_timestamp; - state.exponent = args.exponent; - state.decay_secs = args.decay_secs; - state.target_price = args.target_price; + state.target_timestamp = *args.target_timestamp; + state.exponent = *args.exponent; + state.decay_secs = *args.decay_secs; + state.target_price = *args.target_price; }; - if (!args.rent_days) - args.rent_days = state.rent_days; - if (!args.min_rent_fee.amount && state.min_rent_fee.amount) - args.min_rent_fee = state.min_rent_fee; + if (!args.rent_days) { + *args.rent_days = state.rent_days; + } + + if (!args.min_rent_fee) { + eosio::check(!is_default_asset(state.min_rent_fee), "min_rent_fee does not have a default value"); + *args.min_rent_fee = state.min_rent_fee; + } - eosio::check(args.rent_days > 0, "rent_days must be > 0"); - eosio::check(args.min_rent_fee.symbol == core_symbol, "min_rent_fee doesn't match core symbol"); - eosio::check(args.min_rent_fee.amount > 0, "min_rent_fee must be positive"); + eosio::check(*args.rent_days > 0, "rent_days must be > 0"); + eosio::check(args.min_rent_fee->symbol == core_symbol, "min_rent_fee doesn't match core symbol"); + eosio::check(args.min_rent_fee->amount > 0, "min_rent_fee must be positive"); - state.rent_days = args.rent_days; - state.min_rent_fee = args.min_rent_fee; + state.rent_days = *args.rent_days; + state.min_rent_fee = *args.min_rent_fee; update(state.net, args.net); update(state.cpu, args.cpu); diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index d1d0f98cd..1bef88151 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -16,13 +16,13 @@ inline constexpr int64_t rentbw_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 inline constexpr int64_t stake_weight = 100'000'000'0000ll; // 10^12 struct rentbw_config_resource { - int64_t current_weight_ratio = {}; - int64_t target_weight_ratio = {}; - int64_t assumed_stake_weight = {}; - time_point_sec target_timestamp = {}; - double exponent = {}; - uint32_t decay_secs = {}; - asset target_price = asset{}; + fc::optional current_weight_ratio = {}; + fc::optional target_weight_ratio = {}; + fc::optional assumed_stake_weight = {}; + fc::optional target_timestamp = {}; + fc::optional exponent = {}; + fc::optional decay_secs = {}; + fc::optional target_price = {}; }; FC_REFLECT(rentbw_config_resource, // (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight)(target_timestamp) // @@ -31,8 +31,8 @@ FC_REFLECT(rentbw_config_resource, struct rentbw_config { rentbw_config_resource net = {}; rentbw_config_resource cpu = {}; - uint32_t rent_days = {}; - asset min_rent_fee = asset{}; + fc::optional rent_days = {}; + fc::optional min_rent_fee = {}; }; FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_fee)) @@ -128,7 +128,35 @@ struct rentbw_tester : eosio_system_tester { } action_result configbw(const rentbw_config& config) { - return push_action(config::system_account_name, N(configrentbw), mvo()("args", config)); + // Verbose solution needed to work around bug in abi_serializer that fails if optional values aren't explicitly + // specified with a null value. + + auto optional_to_variant = []( const auto& v ) -> fc::variant { + return (!v ? fc::variant() : fc::variant(*v)); + }; + + auto resource_conf_vo = [&optional_to_variant](const rentbw_config_resource& c ) { + return mvo("current_weight_ratio", optional_to_variant(c.current_weight_ratio)) + ("target_weight_ratio", optional_to_variant(c.target_weight_ratio)) + ("assumed_stake_weight", optional_to_variant(c.assumed_stake_weight)) + ("target_timestamp", optional_to_variant(c.target_timestamp)) + ("exponent", optional_to_variant(c.exponent)) + ("decay_secs", optional_to_variant(c.decay_secs)) + ("target_price", optional_to_variant(c.target_price)) + ; + }; + + auto conf = mvo("net", resource_conf_vo(config.net)) + ("cpu", resource_conf_vo(config.cpu)) + ("rent_days", optional_to_variant(config.rent_days)) + ("min_rent_fee", optional_to_variant(config.min_rent_fee)) + ; + + //idump((fc::json::to_pretty_string(conf))); + return push_action(config::system_account_name, N(configrentbw), mvo()("args", std::move(conf))); + + // If abi_serializer worked correctly, the following is all that would be needed: + //return push_action(config::system_account_name, N(configrentbw), mvo()("args", config)); } action_result rentbwexec(name user, uint16_t max) { @@ -226,11 +254,13 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { push_action(N(alice1111111), N(configrentbw), mvo()("args", make_config()))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("rentbw hasn't been initialized"), rentbwexec(N(alice1111111), 10)); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), - // configbw(make_config([&](auto& c) { c.rent_days = 0; }))); // needed only if rent_days does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), + configbw(make_config([&](auto& c) { c.rent_days = 0; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee doesn't match core symbol"), configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("1000000.000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee does not have a default value"), + configbw(make_config([&](auto& c) { c.min_rent_fee = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("0.0000 TST"); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), @@ -246,8 +276,12 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), configbw(make_config([](auto& c) { c.net.target_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight does not have a default value"), + configbw(make_config([](auto& c) { c.net.assumed_stake_weight = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), configbw(make_config([](auto& c) { c.net.assumed_stake_weight = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), + configbw(make_config([&](auto& c) { c.net.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { c.net.target_timestamp = control->head_block_time(); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { @@ -255,8 +289,10 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), - // configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); // needed only if decay_secs does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price does not have a default value"), + configbw(make_config([&](auto& c) { c.net.target_price = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("1000000.000 TST"); }))); @@ -275,8 +311,12 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), configbw(make_config([](auto& c) { c.cpu.target_weight_ratio = rentbw_frac + 1; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight does not have a default value"), + configbw(make_config([](auto& c) { c.cpu.assumed_stake_weight = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), configbw(make_config([](auto& c) { c.cpu.assumed_stake_weight = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp does not have a default value"), + configbw(make_config([&](auto& c) { c.cpu.target_timestamp = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { c.cpu.target_timestamp = control->head_block_time(); }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_timestamp must be in the future"), configbw(make_config([&](auto& c) { @@ -284,8 +324,10 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("exponent must be >= 1"), configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); - //BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), - // configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); // needed only if decay_secs does not have default + BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), + configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price does not have a default value"), + configbw(make_config([&](auto& c) { c.cpu.target_price = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("1000000.000 TST"); }))); From 9be23747626259ad974b928f2fec180ac6aec87c Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Dec 2019 20:59:30 -0500 Subject: [PATCH 43/78] replace target_price with the more meaningful max_price; also change pricing model to now also include a min_price Note: Assuming min_price is 0, this new price model can be directly compared to the prior one. In fact, under that condition, max_price can be thought of as target_price * exponent. --- .../include/eosio.system/eosio.system.hpp | 15 +- contracts/eosio.system/src/rentbw.cpp | 56 +++-- tests/eosio.rentbw_tests.cpp | 201 ++++++++++++++---- 3 files changed, 208 insertions(+), 64 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index b8abe590a..98b9bf087 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -484,11 +484,15 @@ namespace eosiosystem { // utilization and instantaneous resource utilization to shrink // by 63%. Do not specify to preserve the existing setting or // use the default. - std::optional target_price; // Fee needed to rent the entire resource market weight. Do not - // specify to preserve the existing setting (no default exists). + std::optional min_price; // Fee needed to rent the entire resource market weight at the + // minimum price. Do not specify to preserve the existing + // setting or use the default. + std::optional max_price; // Fee needed to rent the entire resource market weight at the + // maximum price. Do not specify to preserve the existing + // setting (no default exists). EOSLIB_SERIALIZE( rentbw_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) - (target_timestamp)(exponent)(decay_secs)(target_price) ) + (target_timestamp)(exponent)(decay_secs)(min_price)(max_price) ) }; struct rentbw_config { @@ -528,7 +532,10 @@ namespace eosiosystem { double exponent = default_exponent; // Exponent of resource price curve. uint32_t decay_secs = default_decay_secs; // Number of seconds for the gap between adjusted resource // utilization and instantaneous utilization to shrink by 63%. - asset target_price = {}; // Fee needed to rent the entire resource market weight. + asset min_price = {}; // Fee needed to rent the entire resource market weight at + // the minimum price (defaults to 0). + asset max_price = {}; // Fee needed to rent the entire resource market weight at + // the maximum price. int64_t utilization = 0; // Instantaneous resource utilization. This is the current // amount sold. utilization <= weight. int64_t adjusted_utilization = 0; // Adjusted resource utilization. This is >= utilization and diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 98513d96b..6d5d385f3 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -176,9 +176,18 @@ void system_contract::configrentbw(rentbw_config& args) { *args.decay_secs = state.decay_secs; } - if (!args.target_price) { - eosio::check(!is_default_asset(state.target_price), "target_price does not have a default value"); - *args.target_price = state.target_price; + if (!args.max_price) { + eosio::check(!is_default_asset(state.max_price), "max_price does not have a default value"); + *args.max_price = state.max_price; + } + + if (!args.min_price) { + if (is_default_asset(state.min_price)) { + *args.min_price = *args.max_price; // just to copy symbol of max_price + args.min_price->amount = 0; // min_price has a default of zero. + } else { + *args.min_price = state.min_price; + } } eosio::check(*args.current_weight_ratio > 0, "current_weight_ratio is too small"); @@ -190,10 +199,16 @@ void system_contract::configrentbw(rentbw_config& args) { eosio::check(*args.assumed_stake_weight * int128_t(rentbw_frac) / *args.target_weight_ratio <= std::numeric_limits::max(), "assumed_stake_weight/target_weight_ratio is too large"); - eosio::check(*args.exponent >= 1, "exponent must be >= 1"); + eosio::check(*args.exponent >= 1.0, "exponent must be >= 1"); eosio::check(*args.decay_secs >= 1, "decay_secs must be >= 1"); - eosio::check(args.target_price->symbol == core_symbol, "target_price doesn't match core symbol"); - eosio::check(args.target_price->amount > 0, "target_price must be positive"); + eosio::check(args.max_price->symbol == core_symbol, "max_price doesn't match core symbol"); + eosio::check(args.max_price->amount > 0, "max_price must be positive"); + eosio::check(args.min_price->symbol == core_symbol, "min_price doesn't match core symbol"); + eosio::check(args.min_price->amount >= 0, "min_price must be non-negative"); + eosio::check(args.min_price->amount <= args.max_price->amount, "min_price cannot exceed max_price"); + if (*args.exponent == 1.0) { + eosio::check(args.min_price->amount == args.max_price->amount, "min_price and max_price must be the same if the exponent is 1"); + } state.assumed_stake_weight = *args.assumed_stake_weight; state.initial_weight_ratio = *args.current_weight_ratio; @@ -202,7 +217,8 @@ void system_contract::configrentbw(rentbw_config& args) { state.target_timestamp = *args.target_timestamp; state.exponent = *args.exponent; state.decay_secs = *args.decay_secs; - state.target_price = *args.target_price; + state.min_price = *args.min_price; + state.max_price = *args.max_price; }; if (!args.rent_days) { @@ -236,7 +252,9 @@ void system_contract::configrentbw(rentbw_config& args) { } // system_contract::configrentbw /** - * @pre 0 < state.target_price.amount + * @pre 0 == state.min_price.amount (for now) + * @pre 0 <= state.min_price.amount <= state.max_price.amount + * @pre 0 < state.max_price.amount * @pre 1.0 <= state.exponent * @pre 0 <= state.utilization <= state.adjusted_utilization <= state.weight * @pre 0 <= utilization_increase <= (state.weight - state.utilization) @@ -247,26 +265,36 @@ int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_ // Let p(u) = price as a function of the utilization fraction u which is defined for u in [0.0, 1.0]. // Let f(u) = integral of the price function p(x) from x = 0.0 to x = u, again defined for u in [0.0, 1.0]. + // In particular we choose f(u) = min_price * u + ((max_price - min_price) / exponent) * (u ^ exponent). + // And so p(u) = min_price + (max_price - min_price) * (u ^ (exponent - 1.0)). + // Returns f(double(end_utilization)/state.weight) - f(double(start_utilization)/state.weight) which is equivalent to // the integral of p(x) from x = double(start_utilization)/state.weight to x = double(end_utilization)/state.weight. // @pre 0 <= start_utilization <= end_utilization <= state.weight auto price_integral_delta = [&state](int64_t start_utilization, int64_t end_utilization) -> double { - return state.target_price.amount * std::pow(double(end_utilization) / state.weight, state.exponent) - - state.target_price.amount * std::pow(double(start_utilization) / state.weight, state.exponent); + double coefficient = (state.max_price.amount - state.min_price.amount) / state.exponent; + double start_u = double(start_utilization) / state.weight; + double end_u = double(end_utilization) / state.weight; + return state.min_price.amount * end_u - state.min_price.amount * start_u + + coefficient * std::pow(end_u, state.exponent) - coefficient * std::pow(start_u, state.exponent); }; // Returns p(double(utilization)/state.weight). // @pre 0 <= utilization <= state.weight auto price_function = [&state](int64_t utilization) -> double { + double price = state.min_price.amount; // state.exponent >= 1.0, therefore the exponent passed into std::pow is >= 0.0. // Since the exponent passed into std::pow could be 0.0 and simultaneously so could double(utilization)/state.weight, // the safest thing to do is handle that as a special case explicitly rather than relying on std::pow to return 1.0 // instead of triggering a domain error. double new_exponent = state.exponent - 1.0; - if (new_exponent <= 0.0) - return state.target_price.amount; - else - return state.exponent * state.target_price.amount * std::pow(double(utilization) / state.weight, new_exponent); + if (new_exponent <= 0.0) { + return state.max_price.amount; + } else { + price += (state.max_price.amount - state.min_price.amount) * std::pow(double(utilization) / state.weight, new_exponent); + } + + return price; }; double fee = 0.0; diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.rentbw_tests.cpp index 1bef88151..115bfa838 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.rentbw_tests.cpp @@ -22,11 +22,12 @@ struct rentbw_config_resource { fc::optional target_timestamp = {}; fc::optional exponent = {}; fc::optional decay_secs = {}; - fc::optional target_price = {}; + fc::optional min_price = {}; + fc::optional max_price = {}; }; FC_REFLECT(rentbw_config_resource, // (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight)(target_timestamp) // - (exponent)(decay_secs)(target_price)) + (exponent)(decay_secs)(min_price)(max_price)) struct rentbw_config { rentbw_config_resource net = {}; @@ -47,14 +48,15 @@ struct rentbw_state_resource { time_point_sec target_timestamp; double exponent; uint32_t decay_secs; - asset target_price; + asset min_price; + asset max_price; int64_t utilization; int64_t adjusted_utilization; time_point_sec utilization_timestamp; }; FC_REFLECT(rentbw_state_resource, // (version)(weight)(weight_ratio)(assumed_stake_weight)(initial_weight_ratio)(target_weight_ratio) // - (initial_timestamp)(target_timestamp)(exponent)(decay_secs)(target_price)(utilization) // + (initial_timestamp)(target_timestamp)(exponent)(decay_secs)(min_price)(max_price)(utilization) // (adjusted_utilization)(utilization_timestamp)) struct rentbw_state { @@ -99,7 +101,8 @@ struct rentbw_tester : eosio_system_tester { config.net.target_timestamp = control->head_block_time() + fc::days(100); config.net.exponent = 2; config.net.decay_secs = fc::days(1).to_seconds(); - config.net.target_price = asset::from_string("1000000.0000 TST"); + config.net.min_price = asset::from_string("0.0000 TST"); + config.net.max_price = asset::from_string("1000000.0000 TST"); config.cpu.current_weight_ratio = rentbw_frac; config.cpu.target_weight_ratio = rentbw_frac / 100; @@ -107,7 +110,8 @@ struct rentbw_tester : eosio_system_tester { config.cpu.target_timestamp = control->head_block_time() + fc::days(100); config.cpu.exponent = 2; config.cpu.decay_secs = fc::days(1).to_seconds(); - config.cpu.target_price = asset::from_string("1000000.0000 TST"); + config.cpu.min_price = asset::from_string("0.0000 TST"); + config.cpu.max_price = asset::from_string("1000000.0000 TST"); config.rent_days = 30; config.min_rent_fee = asset::from_string("1.0000 TST"); @@ -142,7 +146,8 @@ struct rentbw_tester : eosio_system_tester { ("target_timestamp", optional_to_variant(c.target_timestamp)) ("exponent", optional_to_variant(c.exponent)) ("decay_secs", optional_to_variant(c.decay_secs)) - ("target_price", optional_to_variant(c.target_price)) + ("min_price", optional_to_variant(c.min_price)) + ("max_price", optional_to_variant(c.max_price)) ; }; @@ -291,15 +296,25 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { configbw(make_config([&](auto& c) { c.net.exponent = .999; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), configbw(make_config([&](auto& c) { c.net.decay_secs = 0; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price does not have a default value"), - configbw(make_config([&](auto& c) { c.net.target_price = {}; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { - c.net.target_price = asset::from_string("1000000.000 TST"); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price does not have a default value"), + configbw(make_config([&](auto& c) { c.net.max_price = {}; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.net.max_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price must be positive"), + configbw(make_config([&](auto& c) { c.net.max_price = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price must be positive"), + configbw(make_config([&](auto& c) { c.net.max_price = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.net.min_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price must be non-negative"), + configbw(make_config([&](auto& c) { c.net.min_price = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price cannot exceed max_price"), + configbw(make_config([&](auto& c) { + c.net.min_price = asset::from_string("3.0000 TST"); + c.net.max_price = asset::from_string("2.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("0.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.net.target_price = asset::from_string("-1.0000 TST"); }))); // cpu assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), @@ -326,15 +341,25 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { configbw(make_config([&](auto& c) { c.cpu.exponent = .999; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("decay_secs must be >= 1"), configbw(make_config([&](auto& c) { c.cpu.decay_secs = 0; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price does not have a default value"), - configbw(make_config([&](auto& c) { c.cpu.target_price = {}; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price doesn't match core symbol"), configbw(make_config([&](auto& c) { - c.cpu.target_price = asset::from_string("1000000.000 TST"); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price does not have a default value"), + configbw(make_config([&](auto& c) { c.cpu.max_price = {}; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.cpu.max_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price must be positive"), + configbw(make_config([&](auto& c) { c.cpu.max_price = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("max_price must be positive"), + configbw(make_config([&](auto& c) { c.cpu.max_price = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.cpu.min_price = asset::from_string("1000000.000 TST"); + }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price must be non-negative"), + configbw(make_config([&](auto& c) { c.cpu.min_price = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_price cannot exceed max_price"), + configbw(make_config([&](auto& c) { + c.cpu.min_price = asset::from_string("3.0000 TST"); + c.cpu.max_price = asset::from_string("2.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("0.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("target_price must be positive"), - configbw(make_config([&](auto& c) { c.cpu.target_price = asset::from_string("-1.0000 TST"); }))); } // config_tests FC_LOG_AND_RETHROW() @@ -479,13 +504,15 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { config.net.target_weight_ratio = rentbw_frac; config.net.assumed_stake_weight = stake_weight; config.net.exponent = 1; - config.net.target_price = asset::from_string("1000000.0000 TST"); + config.net.min_price = asset::from_string("1000000.0000 TST"); + config.net.max_price = asset::from_string("1000000.0000 TST"); config.cpu.current_weight_ratio = rentbw_frac; config.cpu.target_weight_ratio = rentbw_frac; config.cpu.assumed_stake_weight = stake_weight; config.cpu.exponent = 1; - config.cpu.target_price = asset::from_string("1000000.0000 TST"); + config.cpu.min_price = asset::from_string("1000000.0000 TST"); + config.cpu.max_price = asset::from_string("1000000.0000 TST"); config.rent_days = 30; config.min_rent_fee = asset::from_string("1.0000 TST"); @@ -500,6 +527,53 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("market doesn't have resources available"), // t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, 0, asset::from_string("1.0000 TST"))); + + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_default_config([&](auto& config) { + // weight = stake_weight + config.net.current_weight_ratio = rentbw_frac/2; + config.net.target_weight_ratio = rentbw_frac/2; + + // weight = stake_weight + config.cpu.current_weight_ratio = rentbw_frac/2; + config.cpu.target_weight_ratio = rentbw_frac/2; + }))); + + auto net_weight = stake_weight; + auto cpu_weight = stake_weight; + + t.start_rex(); + t.create_account_with_resources(N(aaaaaaaaaaaa), config::system_account_name, core_sym::from_string("1.0000"), + false, core_sym::from_string("500.0000"), core_sym::from_string("500.0000")); + + // 10%, 20% + // (.1) * 1000000.0000 = 100000.0000 + // (.2) * 1000000.0000 = 200000.0000 + // total = 300000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("300000.0000")); + t.check_rentbw(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, rentbw_frac * .1, rentbw_frac * .2, + asset::from_string("300000.0000 TST"), net_weight * .1, cpu_weight * .2); + + // Start decay + t.produce_block(fc::days(30) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, .1 * net_weight, 0)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, .2 * cpu_weight, 0)); + + // 2 days of decay from (10%, 20%) to (1.35%, 2.71%) + t.produce_block(fc::days(2) - fc::milliseconds(500)); + BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-2)), + int64_t(.1 * net_weight * exp(-2)) / 1000)); + BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(.2 * cpu_weight * exp(-2)), + int64_t(.2 * cpu_weight * exp(-2)) / 1000)); + + // 2%, 2% + // (0.0135 + 0.02 - 0.0135) * 1000000.0000 = 20000.0000 + // (.02) * 1000000.0000 = 20000.0000 + // total = 40000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("40000.0001")); + t.check_rentbw(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, rentbw_frac * .02, rentbw_frac * .02, + asset::from_string("40000.0001 TST"), net_weight * .02, cpu_weight * .02); } auto init = [](auto& t, bool rex) { @@ -510,14 +584,14 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { config.net.target_weight_ratio = rentbw_frac / 4; config.net.assumed_stake_weight = stake_weight; config.net.exponent = 2; - config.net.target_price = asset::from_string("1000000.0000 TST"); + config.net.max_price = asset::from_string("2000000.0000 TST"); // weight = stake_weight * 4 / 2 config.cpu.current_weight_ratio = rentbw_frac / 5; config.cpu.target_weight_ratio = rentbw_frac / 5; config.cpu.assumed_stake_weight = stake_weight / 2; config.cpu.exponent = 3; - config.cpu.target_price = asset::from_string("2000000.0000 TST"); + config.cpu.max_price = asset::from_string("6000000.0000 TST"); config.rent_days = 30; config.min_rent_fee = asset::from_string("1.0000 TST"); @@ -605,21 +679,57 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { { rentbw_tester t; init(t, true); - // (.3 ^ 2) * 1000000.0000 = 90000.0000 - // (.4 ^ 3) * 2000000.0000 = 128000.0000 - // total = 218000.0000 + // (.3 ^ 2) * 2000000.0000 / 2 = 90000.0000 + // (.4 ^ 3) * 6000000.0000 / 3 = 128000.0000 + // total = 218000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("218000.0001")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .3, rentbw_frac * .4, asset::from_string("218000.0001 TST"), net_weight * .3, cpu_weight * .4); - // (.35 ^ 2) * 1000000.0000 - 90000.0000 = 32500.0000 - // (.5 ^ 3) * 2000000.0000 - 128000.0000 = 122000.0000 - // total = 154500.0000 + // (.35 ^ 2) * 2000000.0000 / 2 - 90000.0000 = 32500.0000 + // (.5 ^ 3) * 6000000.0000 / 3 - 128000.0000 = 122000.0000 + // total = 154500.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("154500.0000")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .05, rentbw_frac * .10, asset::from_string("154500.0000 TST"), net_weight * .05, cpu_weight * .10); } + // net:50%, cpu:50% (but with non-zero min_price and also an exponent of 2 to simplify the math) + { + rentbw_tester t; + init(t, true); + BOOST_REQUIRE_EQUAL("", t.configbw(t.make_default_config([&](auto& config) { + config.cpu.exponent = 2; + config.net.min_price = asset::from_string("1200000.0000 TST"); + config.net.max_price = asset::from_string("2000000.0000 TST"); + + config.cpu.exponent = 2; + config.cpu.min_price = asset::from_string("4000000.0000 TST"); + config.cpu.max_price = asset::from_string("6000000.0000 TST"); + }))); + + // At 0% utilization for both NET and CPU, the cost (in TST) for renting an infinitesimal amount of resources (dr) is + // 1200000.0000 * dr for NET and 4000000.0000 * dr for CPU. + // At 50% utilization for both NET and CPU, the cost (in TST for renting an infinitesimal amount of resources (dr) is + // 1600000.0000 * dr for NET and 5000000.0000 * dr for CPU. + + // The fee for renting 50% of NET (starting from 0% utilization) is expected to be somewhere between + // 1200000.0000 * 0.5 (= 600000.0000) and 1600000.0000 * 0.5 (= 800000.0000). + // In fact, the cost ends up being 700000.0000. + + // The fee for renting 50% of CPU (starting from 0% utilization) is expected to be somewhere between + // 4000000.0000 * 0.5 (= 2000000.0000) and 5000000.0000 * 0.5 (= 2500000.0000). + // In fact, the cost ends up being 2250000.0000. + + + // 1200000.0000 * .5 + (800000.0000 / 2) * (.5 ^ 2) = 700000.0000 + // 4000000.0000 * .5 + (2000000.0000 / 2) * (.5 ^ 2) = 2250000.0000 + // total = 2950000.0000 + t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("2950000.0000")); + t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .5, rentbw_frac * .5, + asset::from_string("2950000.0000 TST"), net_weight * .5, cpu_weight * .5); + } + { // net:100%, cpu:100% rentbw_tester t; @@ -644,9 +754,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // immediate renewal: adjusted_utilization doesn't have time to fall // - // 2 * (1.0 ^ 1) * 1000000.0000 = 2000000.0000 - // 3 * (1.0 ^ 2) * 2000000.0000 = 6000000.0000 - // total = 8000000.0000 + // (1.0 ^ 1) * 2000000.0000 = 2000000.0000 + // (1.0 ^ 2) * 6000000.0000 = 6000000.0000 + // total = 8000000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("8000000.0000")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, asset::from_string("8000000.0000 TST"), 0, 0); @@ -689,9 +799,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // 100% after 2 days of decay // - // [ [2 * ((e^-2) ^ 1)]*(e^-2 - 0.0) + ((1.0) ^ 2) - ((e^-2) ^ 2) ] * 1000000.0000 = 1018315.6389 - // [ [3 * ((e^-2) ^ 2)]*(e^-2 - 0.0) + ((1.0) ^ 3) - ((e^-2) ^ 3) ] * 2000000.0000 = 2009915.0087 - // total = 3028230.6476 + // [ ((e^-2) ^ 1)*(e^-2 - 0.0) + ((1.0) ^ 2)/2 - ((e^-2) ^ 2)/2 ] * 2000000.0000 = 1018315.6389 + // [ ((e^-2) ^ 2)*(e^-2 - 0.0) + ((1.0) ^ 3)/3 - ((e^-2) ^ 3)/3 ] * 6000000.0000 = 2009915.0087 + // total = 3028230.6476 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3028229.8795")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, asset::from_string("3028229.8795 TST"), net_weight, cpu_weight); @@ -702,9 +812,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { init(t, true); // 10%, 20% - // (.1 ^ 2) * 1000000.0000 = 10000.0000 - // (.2 ^ 3) * 2000000.0000 = 16000.0000 - // total = 26000.0000 + // (.1 ^ 2) * 2000000.0000 / 2 = 10000.0000 + // (.2 ^ 3) * 6000000.0000 / 3 = 16000.0000 + // total = 26000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("26000.0002")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .1, rentbw_frac * .2, asset::from_string("26000.0002 TST"), net_weight * .1, cpu_weight * .2); @@ -712,9 +822,9 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { t.produce_block(fc::days(15) - fc::milliseconds(500)); // 20%, 20% - // (.3 ^ 2) * 1000000.0000 - 10000.0000 = 80000.0000 - // (.4 ^ 3) * 2000000.0000 - 16000.0000 = 112000.0000 - // total = 192000.0000 + // (.3 ^ 2) * 2000000.0000 / 2 - 10000.0000 = 80000.0000 + // (.4 ^ 3) * 6000000.0000 / 3 - 16000.0000 = 112000.0000 + // total = 192000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("192000.0001")); t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .2, rentbw_frac * .2, asset::from_string("192000.0001 TST"), net_weight * .2, cpu_weight * .2); @@ -722,7 +832,6 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // Start decay t.produce_block(fc::days(15) - fc::milliseconds(1000)); BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, .3 * net_weight, 0)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, .4 * cpu_weight, 0)); From f19746782a1d703885cac23e2dafb017599eab26 Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 19 Dec 2019 22:58:18 -0500 Subject: [PATCH 44/78] remove unnecessary precondition comment --- contracts/eosio.system/src/rentbw.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/rentbw.cpp index 6d5d385f3..195f53d37 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/rentbw.cpp @@ -252,7 +252,6 @@ void system_contract::configrentbw(rentbw_config& args) { } // system_contract::configrentbw /** - * @pre 0 == state.min_price.amount (for now) * @pre 0 <= state.min_price.amount <= state.max_price.amount * @pre 0 < state.max_price.amount * @pre 1.0 <= state.exponent From 2703fda5e1b3a8b58cead3b081d01a09d33d8283 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 20 Dec 2019 15:26:55 -0500 Subject: [PATCH 45/78] small tweaks to comments --- .../eosio.system/include/eosio.system/eosio.system.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 98b9bf087..06810802d 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -485,10 +485,12 @@ namespace eosiosystem { // by 63%. Do not specify to preserve the existing setting or // use the default. std::optional min_price; // Fee needed to rent the entire resource market weight at the - // minimum price. Do not specify to preserve the existing + // minimum price. For example, this could be set to 0.005% of + // total token supply. Do not specify to preserve the existing // setting or use the default. std::optional max_price; // Fee needed to rent the entire resource market weight at the - // maximum price. Do not specify to preserve the existing + // maximum price. For example, this could be set to 10% of total + // total token supply. Do not specify to preserve the existing // setting (no default exists). EOSLIB_SERIALIZE( rentbw_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) @@ -499,9 +501,9 @@ namespace eosiosystem { rentbw_config_resource net; // NET market configuration rentbw_config_resource cpu; // CPU market configuration std::optional rent_days; // `rentbw` `days` argument must match this. Do not specify to preserve the - // existing setting or use the default. + // existing setting or use the default. std::optional min_rent_fee; // Rental fees below this amount are rejected. Do not specify to preserve the - // existing setting (no default exists). + // existing setting (no default exists). EOSLIB_SERIALIZE( rentbw_config, (net)(cpu)(rent_days)(min_rent_fee) ) }; From 64cc02ddae2dc2a4ac055d47ca1501d00a540a01 Mon Sep 17 00:00:00 2001 From: arhag Date: Fri, 20 Dec 2019 15:27:59 -0500 Subject: [PATCH 46/78] quick fix to comment --- 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 06810802d..5bee876e4 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -490,7 +490,7 @@ namespace eosiosystem { // setting or use the default. std::optional max_price; // Fee needed to rent the entire resource market weight at the // maximum price. For example, this could be set to 10% of total - // total token supply. Do not specify to preserve the existing + // token supply. Do not specify to preserve the existing // setting (no default exists). EOSLIB_SERIALIZE( rentbw_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) From 4c412311cc188438de2c5b4a7701921ec41c7ee8 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 6 Feb 2020 19:49:13 +0200 Subject: [PATCH 47/78] Spliting index.md file, the content thus moved into new sections, index.md has link to those new sections Fix outdated links Small corrections on emphasizing terms, e.g. system contracts or system accounts Some re-ordering of the sections was done due to introductions of the new ones No new content added, thus another tech review or content review is not needed; however annotations of the system contract's classes were added or updated. To avoid double listing of system contracts (in reference doc tree and under core concepts tree) on the main navigation, each system contract class was annotated more thoroughly; these annotations will make their way into the reference doc content. The core concepts subsection in the navigation tree is not needed anymore, core concept are covered by index.md with link to the reference doc --- .../include/eosio.bios/eosio.bios.hpp | 26 +-- .../include/eosio.msig/eosio.msig.hpp | 14 +- .../include/eosio.system/eosio.system.hpp | 27 +-- .../include/eosio.system/exchange_state.hpp | 6 - .../include/eosio.system/native.hpp | 5 - .../include/eosio.system/rex.results.hpp | 6 +- .../include/eosio.token/eosio.token.hpp | 9 +- .../include/eosio.wrap/eosio.wrap.hpp | 26 +-- docs/01_key-concepts/01_system.md | 24 ++ docs/01_key-concepts/02_ram.md | 12 + docs/01_key-concepts/03_cpu.md | 6 + docs/01_key-concepts/04_net.md | 6 + docs/01_key-concepts/05_stake.md | 6 + docs/01_key-concepts/06_vote.md | 6 + ...d-and-deploy.md => 03_build-and-deploy.md} | 37 +-- .../01_upgrading-the-eosio.system-contract.md | 11 +- .../02_how-to-buy-ram.md | 6 +- .../03_how-to-stake.md | 6 +- .../04_how-to-vote.md | 6 +- ...ow-to-create-issue-and-transfer-a-token.md | 8 +- ...-a-multisig-transaction-with-eosio.msig.md | 36 ++- .../07_how-to-use-eosio.wrap.md | 38 ++- docs/index.md | 220 ++---------------- 23 files changed, 200 insertions(+), 347 deletions(-) create mode 100644 docs/01_key-concepts/01_system.md create mode 100644 docs/01_key-concepts/02_ram.md create mode 100644 docs/01_key-concepts/03_cpu.md create mode 100644 docs/01_key-concepts/04_net.md create mode 100644 docs/01_key-concepts/05_stake.md create mode 100644 docs/01_key-concepts/06_vote.md rename docs/{02_build-and-deploy.md => 03_build-and-deploy.md} (67%) rename docs/{03_guides => 04_guides}/01_upgrading-the-eosio.system-contract.md (98%) rename docs/{03_guides => 04_guides}/02_how-to-buy-ram.md (92%) rename docs/{03_guides => 04_guides}/03_how-to-stake.md (93%) rename docs/{03_guides => 04_guides}/04_how-to-vote.md (95%) rename docs/{03_guides => 04_guides}/05_how-to-create-issue-and-transfer-a-token.md (98%) rename docs/{03_guides => 04_guides}/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md (89%) rename docs/{03_guides => 04_guides}/07_how-to-use-eosio.wrap.md (98%) diff --git a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp index 88094b689..643e562c8 100644 --- a/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp +++ b/contracts/eosio.bios/include/eosio.bios/eosio.bios.hpp @@ -7,25 +7,6 @@ #include #include -/** - * EOSIO Contracts - * - * The design of the EOSIO blockchain calls for a number of smart contracts that are run at a - * privileged permission level in order to support functions such as block producer registration and - * voting, token staking for CPU and network bandwidth, RAM purchasing, multi-sig, etc. These smart - * contracts are referred to as the system, token, msig and wrap (formerly known as sudo) contracts. - * - * This repository contains examples of these privileged contracts that are useful when deploying, - * managing, and/or using an EOSIO blockchain. They are provided for reference purposes: - * - eosio.bios - * - eosio.system - * - eosio.msig - * - eosio.wrap - * - * The following unprivileged contract(s) are also part of the system. - * - eosio.token - */ - namespace eosiobios { using eosio::action_wrapper; @@ -85,6 +66,11 @@ namespace eosiobios { (schedule_version)(new_producers)) }; + /** + * The `eosio.bios` is the first sample of system contract provided by `block.one` through the EOSIO platform. It is a minimalist system contract because it only supplies the actions that are absolutely critical to bootstrap a chain and nothing more. This allows for a chain agnostic approach to bootstrapping a chain. + * + * Just like in the `eosio.system` sample contract implementation, there are a few actions which are not implemented at the contract level (`newaccount`, `updateauth`, `deleteauth`, `linkauth`, `unlinkauth`, `canceldelay`, `onerror`, `setabi`, `setcode`), they are just declared in the contract so they will show in the contract's ABI and users will be able to push those actions to the chain via the account holding the `eosio.system` contract, but the implementation is at the EOSIO core level. They are referred to as EOSIO native actions. + */ class [[eosio::contract("eosio.bios")]] bios : public eosio::contract { public: using contract::contract; @@ -182,8 +168,6 @@ namespace eosiobios { [[eosio::action]] void setcode( name account, uint8_t vmtype, uint8_t vmversion, const std::vector& code ) {} - /** @}*/ - /** * Set abi action sets the abi for contract identified by `account` name. Creates an entry in the abi_hash_table * index, with `account` name as key, if it is not already present and sets its value with the abi hash. diff --git a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp index 25c46221e..19f2600cc 100644 --- a/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp +++ b/contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp @@ -6,12 +6,15 @@ #include namespace eosio { - + /** - * @defgroup eosiomsig eosio.msig - * @ingroup eosiocontracts - * eosio.msig contract defines the structures and actions needed to manage the proposals and approvals on blockchain. - * @{ + * The `eosio.msig` system contract allows for 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. + * + * In short, the workflow to propose, review, approve and then executed a transaction 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. */ class [[eosio::contract("eosio.msig")]] multisig : public contract { public: @@ -156,5 +159,4 @@ namespace eosio { typedef eosio::multi_index< "invals"_n, invalidation > invalidations; }; - /** @}*/ // end of @defgroup eosiomsig eosio.msig } /// namespace eosio diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 8dce115d2..0c81cb952 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -78,19 +78,20 @@ namespace eosiosystem { static constexpr int64_t default_inflation_pay_factor = 50000; // producers pay share = 10000 / 50000 = 20% of the inflation static constexpr int64_t default_votepay_factor = 40000; // per-block pay share = 10000 / 40000 = 25% of the producer pay - /** - * eosio.system contract - * - * 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. - * - Producers 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 (REX) allows token holders to lend their tokens, - * and users to rent CPU and Network resources in return for a market-determined fee. - */ - + /** + * The `eosio.system` smart contract is provided by `block.one` as a sample system contract, and it defines the structures and actions needed for blockchain's core functionality. + * + * Just like in the `eosio.bios` sample contract implementation, there are a few actions which are not implemented at the contract level (`newaccount`, `updateauth`, `deleteauth`, `linkauth`, `unlinkauth`, `canceldelay`, `onerror`, `setabi`, `setcode`), they are just declared in the contract so they will show in the contract's ABI and users will be able to push those actions to the chain via the account holding the `eosio.system` contract, but the implementation is at the EOSIO core level. They are referred to as EOSIO native actions. + * + * - Users can stake tokens for CPU and Network bandwidth, and then vote for producers or + * delegate their vote to a proxy. + * - Producers 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 (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: // - a `newname` name that the bid is for // - a `high_bidder` account name that is the one with the highest bid so far diff --git a/contracts/eosio.system/include/eosio.system/exchange_state.hpp b/contracts/eosio.system/include/eosio.system/exchange_state.hpp index 4e5ba8174..c339b9706 100644 --- a/contracts/eosio.system/include/eosio.system/exchange_state.hpp +++ b/contracts/eosio.system/include/eosio.system/exchange_state.hpp @@ -8,11 +8,6 @@ namespace eosiosystem { using eosio::asset; using eosio::symbol; - /** - * @addtogroup eosiosystem - * @{ - */ - /** * Uses Bancor math to create a 50/50 relay between two asset types. * @@ -50,5 +45,4 @@ namespace eosiosystem { }; typedef eosio::multi_index< "rammarket"_n, exchange_state > rammarket; - /** @}*/ // enf of @addtogroup eosiosystem } /// namespace eosiosystem diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index b5cb33e2b..ca885347a 100644 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -17,10 +17,6 @@ namespace eosiosystem { using eosio::permission_level; using eosio::public_key; - /** - * @addtogroup eosiosystem - * @{ - */ /** * A weighted permission. * @@ -264,5 +260,4 @@ namespace eosiosystem { using setcode_action = eosio::action_wrapper<"setcode"_n, &native::setcode>; using setabi_action = eosio::action_wrapper<"setabi"_n, &native::setabi>; }; - /** @}*/ // @addtogroup eosiosystem } diff --git a/contracts/eosio.system/include/eosio.system/rex.results.hpp b/contracts/eosio.system/include/eosio.system/rex.results.hpp index 29af85339..378d6add3 100644 --- a/contracts/eosio.system/include/eosio.system/rex.results.hpp +++ b/contracts/eosio.system/include/eosio.system/rex.results.hpp @@ -9,9 +9,9 @@ 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, + * 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 { diff --git a/contracts/eosio.token/include/eosio.token/eosio.token.hpp b/contracts/eosio.token/include/eosio.token/eosio.token.hpp index 380d11b11..050a685b5 100644 --- a/contracts/eosio.token/include/eosio.token/eosio.token.hpp +++ b/contracts/eosio.token/include/eosio.token/eosio.token.hpp @@ -14,8 +14,13 @@ namespace eosio { using std::string; /** - * eosio.token contract defines the structures and actions that allow users to create, issue, and manage - * tokens on EOSIO based blockchains. + * The `eosio.token` sample system contract defines the structures and actions that allow users to create, issue, and manage tokens for EOSIO based blockchains. It demonstrates one way to implement a smart contract which allows for creation and management of tokens. 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 below 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. 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. */ class [[eosio::contract("eosio.token")]] token : public contract { public: diff --git a/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp b/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp index c6fdbe249..c272c8e2c 100644 --- a/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp +++ b/contracts/eosio.wrap/include/eosio.wrap/eosio.wrap.hpp @@ -6,16 +6,11 @@ namespace eosio { /** - * @defgroup eosiowrap eosio.wrap - * @ingroup eosiocontracts - * eosio.wrap contract simplifies Block Producer superuser actions by making them more readable and easier to audit. - - * 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. - * @{ + * 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. */ class [[eosio::contract("eosio.wrap")]] wrap : public contract { public: @@ -25,18 +20,19 @@ namespace eosio { * Execute action. * * Execute a transaction while bypassing regular authorization checks. + * + * Preconditions: + * - Requires authorization of eosio.wrap which needs to be a privileged account. * + * Postconditions: + * - Deferred transaction RAM usage is billed to 'executer' * + * * @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]] void exec( ignore executer, ignore trx ); using exec_action = eosio::action_wrapper<"exec"_n, &wrap::exec>; }; - /** @}*/ // end of @defgroup eosiowrap eosio.wrap } /// namespace eosio diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md new file mode 100644 index 000000000..b3f6f2df1 --- /dev/null +++ b/docs/01_key-concepts/01_system.md @@ -0,0 +1,24 @@ +--- +content_title: System contracts, system accounts, privileged accounts +link_text: System contracts and accounts, privileged accounts +--- + +At the genesis of an EOSIO based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](../#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `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` system account. + +As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: + +|Account|Privileged|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.| \ No newline at end of file diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md new file mode 100644 index 000000000..b7ecf26db --- /dev/null +++ b/docs/01_key-concepts/02_ram.md @@ -0,0 +1,12 @@ +--- +content_title: RAM as resource +link_text: RAM as resource +--- + +RAM is the memory, storage space, 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 is explained [here](https://developers.eos.io/eosio-home/docs/data-persistence) or a `singleton`, its definition can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/singleton.hpp) and a sample of its usage [here](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.system/include/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). \ No newline at end of file diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md new file mode 100644 index 000000000..43813698e --- /dev/null +++ b/docs/01_key-concepts/03_cpu.md @@ -0,0 +1,6 @@ +--- +content_title: CPU as resource +link_text: CPU as resource +--- + +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. \ No newline at end of file diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md new file mode 100644 index 000000000..a9b5aea14 --- /dev/null +++ b/docs/01_key-concepts/04_net.md @@ -0,0 +1,6 @@ +--- +content_title: NET as resource +link_text: NET as resource +--- + +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. \ No newline at end of file diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md new file mode 100644 index 000000000..c0fb29b28 --- /dev/null +++ b/docs/01_key-concepts/05_stake.md @@ -0,0 +1,6 @@ +--- +content_title: Staking on EOSIO based blockchains +link_text: Staking on EOSIO based blockchains +--- + +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. \ No newline at end of file diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md new file mode 100644 index 000000000..5daaac725 --- /dev/null +++ b/docs/01_key-concepts/06_vote.md @@ -0,0 +1,6 @@ +--- +content_title: Voting on EOSIO based blockchains +link_text: Voting on EOSIO based blockchains +--- + +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. \ No newline at end of file diff --git a/docs/02_build-and-deploy.md b/docs/03_build-and-deploy.md similarity index 67% rename from docs/02_build-and-deploy.md rename to docs/03_build-and-deploy.md index b61b15133..15dab87b0 100644 --- a/docs/02_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -1,22 +1,25 @@ -## How to build the eosio.contracts +--- +content_title: How to build eosio.contracts +link_text: How to build 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 +## 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 +### Build contracts using the build script -##### To build contracts alone +#### 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 +#### 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 +### Build contracts manually To build the `eosio.contracts` execute the following commands. @@ -42,38 +45,38 @@ 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. +### 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. -## How to deploy the eosio.contracts +# How to deploy the eosio.contracts -### To deploy eosio.bios contract execute the following command: +## 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 diff --git a/docs/03_guides/01_upgrading-the-eosio.system-contract.md b/docs/04_guides/01_upgrading-the-eosio.system-contract.md similarity index 98% rename from docs/03_guides/01_upgrading-the-eosio.system-contract.md rename to docs/04_guides/01_upgrading-the-eosio.system-contract.md index 2bd712fb4..51f493758 100644 --- a/docs/03_guides/01_upgrading-the-eosio.system-contract.md +++ b/docs/04_guides/01_upgrading-the-eosio.system-contract.md @@ -1,6 +1,9 @@ -## Upgrading the system contract +--- +content_title: Upgrading the system contract +link_text: Upgrading the system contract +--- -### Indirect method using eosio.msig 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. @@ -12,7 +15,7 @@ The disadvantage of the eosio.msig method is that it requires the proposer to ha For now, it is recommended to use the direct method to upgrade the system contract. -### Direct method (avoids using eosio.msig contract) +# Direct method (avoids using eosio.msig contract) Each of the top 21 block producers should do the following: @@ -206,4 +209,4 @@ $ diff original_system_contract.abi new_system_contract.abi < },{ < "name": "unstaking", < "type": "asset" -``` +``` \ No newline at end of file diff --git a/docs/03_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md similarity index 92% rename from docs/03_guides/02_how-to-buy-ram.md rename to docs/04_guides/02_how-to-buy-ram.md index 2885c5143..cd808e21b 100644 --- a/docs/03_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -1,8 +1,8 @@ -## Goal +# Goal Setup an account that require multiple signatures for signing a transaction -## Before you begin +# Before you begin * You have an account @@ -14,7 +14,7 @@ Setup an account that require multiple signatures for signing a transaction * Unlock your wallet -## Steps +# Steps Buys RAM in value of 0.1 SYS tokens for account `alice`: diff --git a/docs/03_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md similarity index 93% rename from docs/03_guides/03_how-to-stake.md rename to docs/04_guides/03_how-to-stake.md index 83f3a8da7..4cfd98931 100644 --- a/docs/03_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -1,8 +1,8 @@ -## Goal +# Goal Stake resource for your account -## Before you begin +# Before you begin * Install the currently supported version of cleos @@ -13,7 +13,7 @@ Stake resource for your account * What is network bandwidth * What is CPU bandwidth -## Steps +# Steps Stake 0.01 SYS network bandwidth for `alice` diff --git a/docs/03_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md similarity index 95% rename from docs/03_guides/04_how-to-vote.md rename to docs/04_guides/04_how-to-vote.md index 62654ba7c..f1a520f64 100644 --- a/docs/03_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -1,8 +1,8 @@ -## Goal +# Goal Vote for a block producer -## Before you begin +# Before you begin * Install the current supported version of cleos @@ -14,7 +14,7 @@ Vote for a block producer * Unlock your wallet -## Steps +# Steps Assume you are going to vote for blockproducer1 and blockproducer2 from an account called `eosiotestts2`, execute the following: diff --git a/docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md similarity index 98% rename from docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md rename to docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 3693d37e6..313e8139e 100644 --- a/docs/03_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -1,5 +1,3 @@ -## How to create, issue and transfer a token - ## Step 1: Obtain Contract Source Navigate to your contracts directory. @@ -74,7 +72,7 @@ This command created a new token `SYS` with a precision of 4 decimals and a maxi ## Step 6: Issue Tokens -The issuer can issue new tokens to the issuer account in our case `eosio`. +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 @@ -114,7 +112,7 @@ Result: 25.00 SYS ``` -Check "eosio's" balance, notice that tokens were deducted from the account +Check "eosio's" balance, notice that tokens were deducted from the account ```shell cleos get currency balance eosio.token eosio SYS @@ -123,4 +121,4 @@ cleos get currency balance eosio.token eosio SYS Result: ```text 75.00 SYS -``` +``` \ No newline at end of file diff --git a/docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md similarity index 89% rename from docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md rename to docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index f68dff871..6c78c0e16 100644 --- a/docs/03_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -1,14 +1,12 @@ -## 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 @@ -16,7 +14,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 { @@ -57,7 +55,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 @@ -65,7 +63,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 @@ -74,15 +72,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 @@ -90,7 +88,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 { @@ -132,7 +130,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 @@ -140,18 +138,18 @@ 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 ... -SYS balances: +SYS balances: liquid: 1.0487 SYS staked: 2.0000 SYS unstaking: 0.0000 SYS 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 @@ -159,13 +157,13 @@ 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 ... -SYS balances: +SYS balances: liquid: 2.0487 SYS staked: 2.0000 SYS unstaking: 0.0000 SYS total: 4.0487 SYS -```` +```` \ No newline at end of file diff --git a/docs/03_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md similarity index 98% rename from docs/03_guides/07_how-to-use-eosio.wrap.md rename to docs/04_guides/07_how-to-use-eosio.wrap.md index 0f3395fcb..44c404f96 100644 --- a/docs/03_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -1,6 +1,4 @@ -# eosio.wrap - -## 1. Installing the eosio.wrap contract +# 1. Installing the eosio.wrap contract The eosio.wrap contract needs to be installed on a privileged account to function. It is recommended to use the account `eosio.wrap`. @@ -10,9 +8,9 @@ The `eosio.wrap` account also needs to have sufficient RAM to host the contract This guide will be using cleos to carry out the process. -### 1.1 Create the eosio.wrap account +## 1.1 Create the eosio.wrap account -#### 1.1.1 Generate the transaction to create the eosio.wrap account +### 1.1.1 Generate the transaction to create the eosio.wrap account The transaction to create the `eosio.wrap` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. @@ -275,7 +273,7 @@ $ cat producer_permissions.json ] ``` -#### 1.1.2 Propose the transaction to create the eosio.wrap account +### 1.1.2 Propose the transaction to create the eosio.wrap account Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same create_wrap_account_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. @@ -291,7 +289,7 @@ executed transaction: bf6aaa06b40e2a35491525cb11431efd2b5ac94e4a7a9c693c5bf0cfed warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 1.1.3 Review and approve the transaction to create the eosio.wrap account +### 1.1.3 Review and approve the transaction to create the eosio.wrap account Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. @@ -350,7 +348,7 @@ executed transaction: 03a907e2a3192aac0cd040c73db8273c9da7696dc7960de22b1a479ae5 warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 1.1.4 Execute the transaction to create the eosio.wrap account +### 1.1.4 Execute the transaction to create the eosio.wrap account When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). @@ -389,9 +387,9 @@ producers: ``` -### 1.2 Deploy the eosio.wrap contract +## 1.2 Deploy the eosio.wrap contract -#### 1.2.1 Generate the transaction to deploy the eosio.wrap contract +### 1.2.1 Generate the transaction to deploy the eosio.wrap contract The transaction to deploy the contract to the `eosio.wrap` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. @@ -452,7 +450,7 @@ $ head -n 9 deploy_wrap_contract_trx.json This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. The end of sub-section 2.1.1 displayed what the JSON of the active permissions of each of the active block producers would look like given the assumptions about the active block producer set. That JSON was stored in the file producer_permissions.json; if the approvers (i.e. block producers) have not created that file already, they should create that file now as shown at the end of sub-section 2.1.1. -#### 1.2.2 Propose the transaction to deploy the eosio.wrap contract +### 1.2.2 Propose the transaction to deploy the eosio.wrap contract Only one of the potential approvers will need to propose the transaction that was created in the previous sub-section. All the other approvers should still follow the steps in the previous sub-section to generate the same deploy_wrap_contract_trx.json file as all the other approvers. They will need this to compare to the actual proposed transaction prior to approving. @@ -468,7 +466,7 @@ executed transaction: 9e50dd40eba25583a657ee8114986a921d413b917002c8fb2d02e2d670 warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 1.2.3 Review and approve the transaction to deploy the eosio.wrap contract +### 1.2.3 Review and approve the transaction to deploy the eosio.wrap contract Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. @@ -543,7 +541,7 @@ executed transaction: d1e424e05ee4d96eb079fcd5190dd0bf35eca8c27dd7231b59df8e4648 warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 1.2.4 Execute the transaction to create the eosio.wrap account +### 1.2.4 Execute the transaction to create the eosio.wrap account When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). @@ -565,9 +563,9 @@ $ sha256sum contracts/eosio.wrap/eosio.wrap.wasm If the two hashes match then the local WebAssembly code is the one deployed on the blockchain. The retrieved ABI, which was stored in the file retrieved-eosio.wrap.abi, can then be compared to the original ABI of the contract (contracts/eosio.wrap/eosio.wrap.abi) to ensure they are semantically the same. -## 2. Using the eosio.wrap contract +# 2. Using the eosio.wrap contract -### 2.1 Example: Updating owner authority of an arbitrary account +## 2.1 Example: Updating owner authority of an arbitrary account This example will demonstrate how to use the deployed eosio.wrap contract together with the eosio.msig contract to allow a greater than two-thirds supermajority of block producers of an EOSIO blockchain to change the owner authority of an arbitrary account. The example will use cleos: in particular, the `cleos multisig` command, the `cleos set account permission` sub-command, and the `cleos wrap exec` sub-command. However, the guide also demonstrates what to do if the `cleos wrap exec` sub-command is not available. @@ -601,7 +599,7 @@ $ cat producer_permissions.json ] ``` -#### 2.1.1 Generate the transaction to change the owner permission of an account +### 2.1.1 Generate the transaction to change the owner permission of an account The goal of this example is for the block producers to change the owner permission of the account `alice`. @@ -742,7 +740,7 @@ Then modify the transaction in wrap_update_alice_owner_trx.json as follows: * append the hex data from update_alice_owner_trx_serialized.hex to the end of the existing hex data in the `data` field in wrap_update_alice_owner_trx.json. -#### 2.1.2 Propose the transaction to change the owner permission of an account +### 2.1.2 Propose the transaction to change the owner permission of an account The lead block producer (`blkproducera`) should propose the transaction stored in wrap_update_alice_owner_trx.json: ``` @@ -752,7 +750,7 @@ executed transaction: 10474f52c9e3fc8e729469a577cd2fc9e4330e25b3fd402fc738ddde26 warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 2.1.3 Review and approve the transaction to change the owner permission of an account +### 2.1.3 Review and approve the transaction to change the owner permission of an account Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. ``` @@ -835,7 +833,7 @@ executed transaction: 2bddc7747e0660ba26babf95035225895b134bfb2ede32ba0a2bb6091c warning: transaction executed locally, but may not be confirmed by the network yet ``` -#### 2.1.4 Execute the transaction to change the owner permission of an account +### 2.1.4 Execute the transaction to change the owner permission of an account When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). @@ -871,4 +869,4 @@ cpu bandwidth: producers: -``` +``` \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 9ef079987..37759d127 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,211 +1,27 @@ -## About System Contracts +--- +content_title: 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. +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. -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. +1. [eosio.bios](action-reference/eosio.bios) +2. [eosio.system](action-reference/eosio.system) +3. [eosio.msig](action-reference/eosio.msig) +4. [eosio.token](action-reference/eosio.token) +5. [eosio.wrap](action-reference/eosio.wrap) -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. +## Key Concepts Implemented by eosio.system -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. +1. [System](01_key-concepts/01_system.md) +2. [RAM](01_key-concepts/02_ram.md) +3. [CPU](01_key-concepts/03_cpu.md) +4. [NET](01_key-concepts/04_net.md) +5. [Stake](01_key-concepts/05_stake.md) +6. [Vote](01_key-concepts/06_vote.md) -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 +## Build and deploy +To build and deploy the system contract follow the instruction from [Build and deploy](03_build-and-deploy.md) section. \ No newline at end of file From b4dd8ad970e846e447fe8cb0f77f82ea5f766768 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 6 Feb 2020 15:15:14 -0500 Subject: [PATCH 48/78] Improve environment logging. Use eosio dependency as declared. --- .cicd/build.sh | 12 ++++++------ .cicd/helpers/dependency-info.sh | 10 ++++++++-- .cicd/test.sh | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.cicd/build.sh b/.cicd/build.sh index 1be513f82..42975cd05 100755 --- a/.cicd/build.sh +++ b/.cicd/build.sh @@ -4,7 +4,7 @@ set -eo pipefail . ./.cicd/helpers/general.sh . ./.cicd/helpers/dependency-info.sh mkdir -p $BUILD_DIR -DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} +DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$SANITIZED_EOSIO_VERSION} if [[ "$BUILDKITE" == 'true' ]]; then buildkite-agent meta-data set cdt-url "$CDT_URL" buildkite-agent meta-data set cdt-version "$CDT_VERSION" @@ -16,15 +16,15 @@ else fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="dpkg -i $MOUNTED_DIR/eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/\\\$(ls /usr/opt/eosio.cdt/)/bin:\\\$PATH" -PRE_COMMANDS="$CDT_COMMANDS && cd $MOUNTED_DIR/build" +PRE_COMMANDS="$CDT_COMMANDS && cd /root/eosio/ && printf \\\"EOSIO commit: \\\$(git rev-parse --verify HEAD). Click \033]1339;url=https://github.com/EOSIO/eos/commit/\\\$(git rev-parse --verify HEAD);content=here\a for details.\n\\\" && cd $MOUNTED_DIR/build" BUILD_COMMANDS="cmake -DBUILD_TESTS=true .. && make -j $JOBS" COMMANDS="$PRE_COMMANDS && $BUILD_COMMANDS" # Test CDT binary download to prevent failures due to eosio.cdt pipeline. INDEX='1' echo "$ curl -sSf $CDT_URL --output eosio.cdt.deb" while ! $(curl -sSf $CDT_URL --output eosio.cdt.deb); do - echo "ERROR: Expected CDT binary for commit ${CDT_COMMIT:0:7} from $CDT_VERSION. It does not exist at $CDT_URL!" - printf "There must be a successful build against ${CDT_COMMIT:0:7} \033]1339;url=https://buildkite.com/EOSIO/eosio-dot-cdt/builds?commit=$CDT_COMMIT;content=here\a for this package to exist.\n" + echo "ERROR: Expected CDT binary for commit ${CDT_COMMIT} from $CDT_VERSION. It does not exist at $CDT_URL!" + printf "There must be a successful build against ${CDT_COMMIT} \033]1339;url=https://buildkite.com/EOSIO/eosio-dot-cdt/builds?commit=$CDT_COMMIT;content=here\a for this package to exist.\n" echo "Attempt $INDEX, retry in 60 seconds..." echo '' INDEX=$(( $INDEX + 1 )) @@ -34,8 +34,8 @@ done 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=$EOSIO_COMMIT;content=here\a for this container to exist.\n" + echo "ERROR: Docker image \"$DOCKER_IMAGE\" not found for eosio \"$EOSIO_VERSION\""'!' + printf "There must be a successful build against ${EOSIO_VERSION} \033]1339;url=${EOSIO_BK_URL};content=here\a for this container to exist.\n" echo "Attempt $INDEX, retry in 60 seconds..." echo '' INDEX=$(( $INDEX + 1 )) diff --git a/.cicd/helpers/dependency-info.sh b/.cicd/helpers/dependency-info.sh index c0f526ac3..ef7e1d052 100755 --- a/.cicd/helpers/dependency-info.sh +++ b/.cicd/helpers/dependency-info.sh @@ -9,6 +9,7 @@ if [[ -f "$RAW_PIPELINE_CONFIG" ]]; then cat "$RAW_PIPELINE_CONFIG" | grep -Po '^[^"/]*("((?<=\\).|[^"])*"[^"/]*)*' | jq -c .\"eosio-dot-contracts\" > "$PIPELINE_CONFIG" CDT_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies."eosio.cdt"') EOSIO_VERSION=$(cat "$PIPELINE_CONFIG" | jq -r '.dependencies.eosio') + SANITIZED_EOSIO_VERSION=$(echo $EOSIO_VERSION | sed 's/\//\_/') else echo 'ERROR: No pipeline configuration file or dependencies file found!' exit 1 @@ -29,6 +30,11 @@ else EOSIO_COMMIT=$(git rev-parse --verify HEAD) cd .. fi -echo "Using eosio ${EOSIO_COMMIT:0:7} from \"$EOSIO_VERSION\"..." -echo "Using cdt ${CDT_COMMIT:0:7} from \"$CDT_VERSION\"..." +if [[ "$EOSIO_COMMIT" == "$EOSIO_VERSION" ]]; then + EOSIO_BK_URL="https://buildkite.com/EOSIO/eosio/builds?commit=${EOSIO_COMMIT}" +else + EOSIO_BK_URL="https://buildkite.com/EOSIO/eosio/builds?branch=${EOSIO_VERSION}" +fi +echo "Using eosio \"$EOSIO_VERSION\"..." +echo "Using cdt ${CDT_COMMIT} 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/.cicd/test.sh b/.cicd/test.sh index 613890358..ea0d181e4 100755 --- a/.cicd/test.sh +++ b/.cicd/test.sh @@ -9,7 +9,7 @@ if [[ "$BUILDKITE" == 'true' ]]; then DOCKER_IMAGE="$(buildkite-agent meta-data get docker-image)" else # Actions . ./.cicd/helpers/dependency-info.sh - DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$EOSIO_COMMIT} + DOCKER_IMAGE=${DOCKER_IMAGE:-eosio/ci-contracts-builder:base-ubuntu-18.04-$SANITIZED_EOSIO_VERSION} fi ARGS=${ARGS:-"--rm -v $(pwd):$MOUNTED_DIR"} CDT_COMMANDS="dpkg -i $MOUNTED_DIR/eosio.cdt.deb && export PATH=/usr/opt/eosio.cdt/$CDT_VERSION/bin:\\\$PATH" @@ -18,6 +18,7 @@ TEST_COMMANDS="ctest -j $JOBS --output-on-failure -T Test" COMMANDS="$PRE_COMMANDS && $TEST_COMMANDS" curl -sSf $CDT_URL --output eosio.cdt.deb set +e +echo "docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\"" eval docker run $ARGS $(buildkite-intrinsics) $DOCKER_IMAGE bash -c \"$COMMANDS\" EXIT_STATUS=$? # buildkite From df2d5d1b01221044202334f5dce46be5acc39405 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 7 Feb 2020 23:15:15 +0200 Subject: [PATCH 49/78] Add explicit titles --- docs/04_guides/02_how-to-buy-ram.md | 5 +++++ docs/04_guides/03_how-to-stake.md | 5 +++++ docs/04_guides/04_how-to-vote.md | 5 +++++ .../04_guides/05_how-to-create-issue-and-transfer-a-token.md | 5 +++++ .../06_how-to-sign-a-multisig-transaction-with-eosio.msig.md | 5 +++++ docs/04_guides/07_how-to-use-eosio.wrap.md | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/docs/04_guides/02_how-to-buy-ram.md b/docs/04_guides/02_how-to-buy-ram.md index cd808e21b..dee6776e8 100644 --- a/docs/04_guides/02_how-to-buy-ram.md +++ b/docs/04_guides/02_how-to-buy-ram.md @@ -1,3 +1,8 @@ +--- +content_title: How to buy RAM +link_text: How to buy RAM +--- + # Goal Setup an account that require multiple signatures for signing a transaction diff --git a/docs/04_guides/03_how-to-stake.md b/docs/04_guides/03_how-to-stake.md index 4cfd98931..0413a01a9 100644 --- a/docs/04_guides/03_how-to-stake.md +++ b/docs/04_guides/03_how-to-stake.md @@ -1,3 +1,8 @@ +--- +content_title: How to stake +link_text: How to stake +--- + # Goal Stake resource for your account diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index f1a520f64..0141d1568 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -1,3 +1,8 @@ +--- +content_title: How to vote +link_text: How to vote +--- + # Goal Vote for a block producer diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index 313e8139e..a09c63d2a 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -1,3 +1,8 @@ +--- +content_title: How to create, issue and transfer a token +link_text: How to create, issue and transfer a token +--- + ## Step 1: Obtain Contract Source Navigate to your contracts directory. diff --git a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 6c78c0e16..89760cda7 100644 --- a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -1,3 +1,8 @@ +--- +content_title: How to sign a multisig transaction with eosio.msig +link_text: How to sign a multisig transaction with eosio.msig +--- + ## Cleos usage example for issuing tokens. ### Prerequisites: diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index 44c404f96..347be4e2c 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -1,3 +1,8 @@ +--- +content_title: How to use eosio.wrap +link_text: How to use eosio.wrap +--- + # 1. Installing the eosio.wrap contract The eosio.wrap contract needs to be installed on a privileged account to function. It is recommended to use the account `eosio.wrap`. From fc3c66d7ee7b3f3330b3a983c68317dd0516d6b8 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Tue, 11 Feb 2020 18:55:20 +0200 Subject: [PATCH 50/78] fix a few broken links in eosio.contracts documentation --- docs/01_key-concepts/02_ram.md | 2 +- docs/03_build-and-deploy.md | 4 ++-- docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index b7ecf26db..63055a464 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -3,7 +3,7 @@ content_title: RAM as resource link_text: RAM as resource --- -RAM is the memory, storage space, 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 is explained [here](https://developers.eos.io/eosio-home/docs/data-persistence) or a `singleton`, its definition can be found [here](https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/singleton.hpp) and a sample of its usage [here](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.system/include/eosio.system/eosio.system.hpp). +RAM is the memory, storage space, 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 is explained [here](https://developers.eos.io/manuals/eosio.cdt/latest/group__multiindex) and its usages [here](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index) or a `singleton`, with its definition found [here](https://developers.eos.io/manuals/eosio.cdt/latest/group__singleton/#singleton-table) and a sample of its usage [here](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton). 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. diff --git a/docs/03_build-and-deploy.md b/docs/03_build-and-deploy.md index 15dab87b0..b2db104ff 100644 --- a/docs/03_build-and-deploy.md +++ b/docs/03_build-and-deploy.md @@ -4,7 +4,7 @@ link_text: How to build 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 +Ensure an appropriate version of `eosio.cdt` is installed. Installing `eosio.cdt` from binaries is sufficient, follow the [`eosio.cdt` installation instructions steps](https://developers.eos.io/manuals/eosio.cdt/latest/installation) to install it. To verify if you have `eosio.cdt` installed and its version run the following command ```sh eosio-cpp -v @@ -16,7 +16,7 @@ eosio-cpp -v 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`. +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://developers.eos.io/manuals/eos/latest/install/build-from-source) 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 diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index a09c63d2a..ca08d5a59 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -106,7 +106,7 @@ executed transaction: 60d334850151cb95c35fe31ce2e8b536b51441c5fd4c3f2fea98edcc6d # 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) +Now check if "bob" got the tokens using [cleos get currency balance](https://developers.eos.io/manuals/eos/latest/cleos/command-reference/get/currency-balance) ```shell cleos get currency balance eosio.token bob SYS From 66fccf6dc565fbeaa3ec3c77c2ac9a01aa883f46 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Wed, 12 Feb 2020 16:42:55 +0200 Subject: [PATCH 51/78] correct the msig how to title --- .../06_how-to-sign-a-multisig-transaction-with-eosio.msig.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 89760cda7..9a20e7a1b 100644 --- a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -3,7 +3,7 @@ content_title: How to sign a multisig transaction with eosio.msig link_text: How to sign a multisig transaction with eosio.msig --- -## Cleos usage example for issuing tokens. +### eosio.msig ### Prerequisites: - eosio.token contract installed to eosio.token account, eosio.msig contract installed on eosio.msig account which is a priviliged account. From e4ed7639723106fbd889e8901077bd72f1e0d37c Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Mon, 24 Feb 2020 10:15:49 -0500 Subject: [PATCH 52/78] Actions now recognizes when all jobs are skipped. --- .github/workflows/main.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a669a810e..c5e107359 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,19 +2,10 @@ name: Pull Request on: [pull_request] jobs: - start-job: - name: Start Job - runs-on: ubuntu-latest - steps: - - name: Start Job. - run: echo "PR created. Builds will be triggered here for forked PRs or Buildkite for internal PRs." - - ubuntu-1804-build: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id name: Ubuntu 18.04 | Build runs-on: ubuntu-latest - needs: start-job steps: - name: Checkout uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e From e9bd3a6154fffff140f539c6f4606681fdc6b7b3 Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Wed, 26 Feb 2020 16:22:46 -0500 Subject: [PATCH 53/78] Fix reruns on forked PRs. --- .github/workflows/main.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c5e107359..1aae0f2b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,9 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + run: | + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge + git submodule sync --recursive + git submodule update --init --force --recursive - name: Build run: | ./.cicd/build.sh @@ -26,9 +29,12 @@ jobs: needs: ubuntu-1804-build steps: - name: Checkout - uses: actions/checkout@50fbc622fc4ef5163becd7fab6573eac35f8462e - with: - submodules: recursive + run: | + git clone https://github.com/${GITHUB_REPOSITORY} . + git fetch -v --prune origin +refs/pull/${PR_NUMBER}/merge:refs/remotes/pull/${PR_NUMBER}/merge + git checkout --force --progress refs/remotes/pull/${PR_NUMBER}/merge + git submodule sync --recursive + git submodule update --init --force --recursive - name: Download Build Artifact uses: actions/download-artifact@v1 with: From 72a6bdd8443087882de50589272e3d9b0815758b Mon Sep 17 00:00:00 2001 From: Scott Arnette Date: Thu, 27 Feb 2020 11:27:38 -0500 Subject: [PATCH 54/78] Fix missing env for Actions. --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1aae0f2b2..12bf291e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,9 @@ name: Pull Request on: [pull_request] +env: + PR_NUMBER: ${{ toJson(github.event.number) }} + jobs: ubuntu-1804-build: if: github.event.pull_request.base.repo.id != github.event.pull_request.head.repo.id From 84ca63e58ca8107a024705df589f874ede32b384 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Mon, 9 Mar 2020 14:42:23 +0200 Subject: [PATCH 55/78] resolves #1 delete README.md because is redundant with docs information and it is a reminiscence of the past docs structure --- contracts/eosio.system/README.md | 185 ------------------------------- 1 file changed, 185 deletions(-) delete mode 100755 contracts/eosio.system/README.md diff --git a/contracts/eosio.system/README.md b/contracts/eosio.system/README.md deleted file mode 100755 index 9e8c0fa63..000000000 --- a/contracts/eosio.system/README.md +++ /dev/null @@ -1,185 +0,0 @@ -eosio.system ----------- - -This contract provides multiple functionalities: -- Users can stake tokens for CPU and Network bandwidth, and then vote for producers or delegate their vote to a proxy. -- Producers 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 (REX) allows token holders to lend their tokens, and users to rent CPU and Network resources in return for a market-determined fee. - -Actions: -The naming convention is codeaccount::actionname followed by a list of paramters. - -## eosio::regproducer producer producer_key url location - - Indicates that a particular account wishes to become a producer - - **producer** account registering to be a producer candidate - - **producer_key** producer account public key - - **url** producer URL - - **location** currently unused index - -## eosio::voteproducer voter proxy producers - - **voter** the account doing the voting - - **proxy** proxy account to whom voter delegates vote - - **producers** list of producers voted for. A maximum of 30 producers is allowed - - Voter can vote for a proxy __or__ a list of at most 30 producers. Storage change is billed to `voter`. - -## eosio::regproxy proxy is_proxy - - **proxy** the account registering as voter proxy (or unregistering) - - **is_proxy** if true, proxy is registered; if false, proxy is unregistered - - Storage change is billed to `proxy`. - -## eosio::delegatebw from receiver stake\_net\_quantity stake\_cpu\_quantity transfer - - **from** account holding tokens to be staked - - **receiver** account to whose resources staked tokens are added - - **stake\_net\_quantity** tokens staked for NET bandwidth - - **stake\_cpu\_quantity** tokens staked for CPU bandwidth - - **transfer** if true, ownership of staked tokens is transfered to `receiver` - - All producers `from` account has voted for will have their votes updated immediately. - -## eosio::undelegatebw from receiver unstake\_net\_quantity unstake\_cpu\_quantity - - **from** account whose tokens will be unstaked - - **receiver** account to whose benefit tokens have been staked - - **unstake\_net\_quantity** tokens to be unstaked from NET bandwidth - - **unstake\_cpu\_quantity** tokens to be unstaked from CPU bandwidth - - Unstaked tokens are transferred to `from` liquid balance via a deferred transaction with a delay of 3 days. - - If called during the delay period of a previous `undelegatebw` action, pending action is canceled and timer is reset. - - All producers `from` account has voted for will have their votes updated immediately. - - Bandwidth and storage for the deferred transaction are billed to `from`. - -## eosio::onblock header - - This special action is triggered when a block is applied by a given producer, and cannot be generated from - any other source. It is used increment the number of unpaid blocks by a producer and update producer schedule. - -## eosio::claimrewards producer - - **producer** producer account claiming per-block and per-vote rewards - -## eosio::deposit owner amount - - Deposits tokens to user REX fund - - **owner** REX fund owner account - - **amount** amount of tokens to be deposited - - An inline transfer from 'owner' liquid balance is executed. - - All REX-related costs and proceeds are deducted from and added to 'owner' REX fund, with one exception being buying REX using staked tokens. - - Storage change is billed to 'owner'. - -## eosio::withdraw owner amount - - Withdraws tokens from user REX fund - - **owner** REX fund owner account - - **amount** amount of tokens to be withdrawn - - An inline transfer to 'owner' liquid balance is executed. - -## eosio::buyrex from amount - - Buys REX in exchange for tokens taken out of user REX fund - - **from** owner account name - - **amount** amount of tokens to be used for purchase - - 'amount' tokens are taken out of 'from' REX fund. - - User must vote for at least 21 producers or delegate vote to proxy before buying REX. - - Tokens used in purchase are added to user's voting power. - - Bought REX cannot be sold before 4 days counting from end of day of purchase. - - Storage change is billed to 'from' account. - - By buying REX, user is lending tokens in order to be rented as CPU or NET resourses. - -## eosio::unstaketorex owner receiver from\_net from\_cpu - - Buys REX using staked tokens - - **owner** owner of staked tokens - - **receiver** account name that tokens have previously been staked to - - **from_net** amount of tokens to be unstaked from NET bandwidth and used for REX purchase - - **from_cpu** amount of tokens to be unstaked from CPU bandwidth and used for REX purchase - - User must vote for at least 21 producers or delegate vote to proxy before buying REX. - - Tokens used in purchase are added to user's voting power. - - Bought REX cannot be sold before 4 days counting from end of day of purchase. - - Storage change is billed to 'owner' account. - -## eosio::sellrex from rex - - Sells REX in exchange for core tokens - - **from** owner account of REX - - **rex** amount of REX to be sold - - Proceeds are deducted from user's voting power. - - If cannot be processed immediately, sell order is added to a queue and will be processed within 30 days at most. - - In case sell order is queued, storage change is billed to 'from' account. - -## eosio::cnclrexorder owner - - Cancels unfilled REX sell order by owner if one exists. - - **owner** owner account name - -## eosio::mvtosavings owner rex - - Moves REX to owner's REX savings bucket - - REX held in savings bucket does not mature and cannot be sold directly - - REX is moved out from the owner's maturity buckets as necessary starting with the bucket with furthest maturity date - - **owner** owner account of REX - - **rex** amount of REX to be moved to savings bucket - -## eosio::mvfrsavings owner rex - - Moves REX from owner's savings bucket to a bucket with a maturity date that is 4 days after the end of the day - - This action is required if the owner wants to sell REX held in savings bucket - - **owner** owner account of REX - - **rex** amount of REX to be moved from savings bucket - -## eosio::rentcpu from receiver loan\_payment loan\_fund - - Rents CPU resources for 30 days in exchange for market-determined price - - **from** account creating and paying for CPU loan - - **receiver** account receiving rented CPU resources - - **loan_payment** tokens paid for the loan - - **loan_fund** additional tokens (can be zero) added to loan fund and used later for loan renewal - - Rents as many core tokens as determined by market price and stakes them for CPU bandwidth for the benefit of `receiver` account. - - `loan_payment` is used for renting, it has to be greater than zero. Amount of rented resources is calculated from `loan_payment`. - - After 30 days the rented core delegation of CPU will expire or be renewed at new market price depending on available loan fund. - - `loan_fund` can be zero, and is added to loan balance. Loan balance represents a reserve that is used at expiration for automatic loan renewal. - - 'from' account can add tokens to loan balance using action `fundcpuloan` and withdraw from loan balance using `defcpuloan`. - - 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 is refunded any remaining balance. - -## eosio::rentnet from receiver loan\_payment loan\_fund - - Rents Network resources for 30 days in exchange for market-determined price - - **from** account creating and paying for Network loan - - **receiver** account receiving rented Network resources - - **loan_payment** tokens paid for the loan - - **loan_fund** additional tokens (can be zero) added to loan fund and used later for loan renewal - - Rents as many core tokens as determined by market price and stakes them for Network bandwidth for the benefit of `receiver` account. - - `loan_payment` is used for renting, it has to be greater than zero. Amount of rented resources is calculated from `loan_payment`. - - After 30 days the rented core delegation of Network will expire or be renewed at new market price depending on available loan fund. - - `loan_fund` can be zero, and is added to loan balance. Loan balance represents a reserve that is used at expiration for automatic loan renewal. - - 'from' account can add tokens to loan balance using action `fundnetloan` and withdraw from loan balance using `defnetloan`. - - 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 is refunded any remaining balance. - -## eosio::fundcpuloan from loan\_num payment - - Transfers tokens from REX fund to the fund of a specific CPU loan in order to be used for loan renewal at expiry - - **from** loan creator account - - **loan_num** loan id - - **payment** tokens transfered from REX fund to loan fund - -## eosio::fundnetloan from loan\_num payment - - Transfers tokens from REX fund to the fund of a specific Network loan in order to be used for loan renewal at expiry - - **from** loan creator account - - **loan_num** loan id - - **payment** tokens transfered from REX fund to loan fund - -## eosio::defcpuloan from loan\_num amount - - Withdraws tokens from the fund of a specific CPU loan and adds them to REX fund - - **from** loan creator account - - **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 - - **from** loan creator account - - **loan_num** loan id - - **amount** tokens transfered from NET loan fund to REX fund - -## eosio::updaterex owner - - Updates REX owner vote weight to current value of held REX - - **owner** REX owner account - -## eosio::rexexec user max - - Performs REX maintenance by processing a specified number of REX sell orders and expired loans - - **user** any account can execute this action - - **max** number of each of CPU loans, NET loans, and sell orders to be processed - -## eosio::consolidate owner - - Consolidates REX maturity buckets into one bucket that cannot be sold before 4 days - - **owner** REX owner account name - -## eosio::closerex owner - - Deletes unused REX-related database entries and frees occupied RAM - - **owner** user account name - - If owner has a non-zero REX balance, the action fails; otherwise, owner REX balance entry is deleted. - - If owner has no outstanding loans and a zero REX fund balance, REX fund entry is deleted. From 1a474c7f334a45ef3f6448cb657bce0716b77cc7 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Mon, 9 Mar 2020 22:46:55 -0400 Subject: [PATCH 56/78] fix build and deploy link in README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b8a32ae4b..21ecb6328 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Dependencies: * [eosio.cdt v1.7.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.7.0) * [eosio v2.0.x](https://github.com/EOSIO/eos/releases/tag/v2.0.1) (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). +## Build + +To build the contracts follow the instructions in [Build and deploy](https://developers.eos.io/manuals/eosio.contracts/latest/build-and-deploy) section. ## Contributing From dd4f523c21cf431abcdf26e057fba80d500cd716 Mon Sep 17 00:00:00 2001 From: arhag Date: Wed, 20 May 2020 16:21:25 -0400 Subject: [PATCH 57/78] use yield function to fix tests to work with EOSIO v2.0.5 and later --- tests/eosio.msig_tests.cpp | 12 ++++---- tests/eosio.system_tester.hpp | 54 +++++++++++++++++------------------ tests/eosio.system_tests.cpp | 32 ++++++++++----------- tests/eosio.token_tests.cpp | 8 +++--- tests/eosio.wrap_tests.cpp | 6 ++-- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/tests/eosio.msig_tests.cpp b/tests/eosio.msig_tests.cpp index cbc614b9f..89f7dbc93 100644 --- a/tests/eosio.msig_tests.cpp +++ b/tests/eosio.msig_tests.cpp @@ -36,7 +36,7 @@ class eosio_msig_tester : public tester { const auto& accnt = control->db().get( N(eosio.msig) ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer_max_time); + abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); } transaction_trace_ptr create_account_with_resources( account_name a, account_name creator, asset ramfunds, bool multisig, @@ -138,7 +138,7 @@ class eosio_msig_tester : public tester { action act; act.account = N(eosio.msig); act.name = name; - act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); + act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer::create_yield_function(abi_serializer_max_time) ); //std::cout << "test:\n" << fc::to_hex(act.data.data(), act.data.size()) << " size = " << act.data.size() << std::endl; return base_tester::push_action( std::move(act), auth ? uint64_t(signer) : 0 ); @@ -174,7 +174,7 @@ transaction eosio_msig_tester::reqauth( account_name from, const vectordb().get( N(eosio.token) ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - token_abi_ser.set_abi(abi, abi_serializer_max_time); + token_abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); } } @@ -69,7 +69,7 @@ class eosio_system_tester : public TESTER { const auto& accnt = control->db().get( config::system_account_name ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer_max_time); + abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); } } @@ -273,7 +273,7 @@ class eosio_system_tester : public TESTER { action act; act.account = config::system_account_name; act.name = name; - act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); + act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer::create_yield_function(abi_serializer_max_time) ); return base_tester::push_action( std::move(act), (auth ? signer : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)).to_uint64_t() ); } @@ -580,7 +580,7 @@ class eosio_system_tester : public TESTER { data.resize( itr->value.size() ); memcpy( data.data(), itr->value.data(), data.size() ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_loan", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_loan", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_last_cpu_loan() { @@ -594,7 +594,7 @@ class eosio_system_tester : public TESTER { fc::variant get_loan_info( const uint64_t& loan_num, bool cpu ) const { name table_name = cpu ? N(cpuloan) : N(netloan); vector data = get_row_by_account( config::system_account_name, config::system_account_name, table_name, account_name(loan_num) ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_loan", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_loan", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_cpu_loan( const uint64_t loan_num ) const { @@ -607,42 +607,42 @@ class eosio_system_tester : public TESTER { fc::variant get_dbw_obj( const account_name& from, const account_name& receiver ) const { 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); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant("delegated_bandwidth", data, abi_serializer::create_yield_function(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(); + return data.empty() ? asset(0, symbol(SY(4, REX))) : abi_ser.binary_to_variant("rex_balance", data, abi_serializer::create_yield_function(abi_serializer_max_time))["rex_balance"].as(); } fc::variant get_rex_balance_obj( 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() ? fc::variant() : abi_ser.binary_to_variant("rex_balance", data, abi_serializer_max_time); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant("rex_balance", data, abi_serializer::create_yield_function(abi_serializer_max_time)); } asset get_rex_fund( const account_name& act ) const { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rexfund), act ); - return data.empty() ? asset(0, symbol{CORE_SYM}) : abi_ser.binary_to_variant("rex_fund", data, abi_serializer_max_time)["balance"].as(); + return data.empty() ? asset(0, symbol{CORE_SYM}) : abi_ser.binary_to_variant("rex_fund", data, abi_serializer::create_yield_function(abi_serializer_max_time))["balance"].as(); } fc::variant get_rex_fund_obj( const account_name& act ) const { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rexfund), act ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_fund", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_fund", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } asset get_rex_vote_stake( 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() ? core_sym::from_string("0.0000") : abi_ser.binary_to_variant("rex_balance", data, abi_serializer_max_time)["vote_stake"].as(); + return data.empty() ? core_sym::from_string("0.0000") : abi_ser.binary_to_variant("rex_balance", data, abi_serializer::create_yield_function(abi_serializer_max_time))["vote_stake"].as(); } fc::variant get_rex_order( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rexqueue), act ); - return abi_ser.binary_to_variant( "rex_order", data, abi_serializer_max_time ); + return abi_ser.binary_to_variant( "rex_order", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_rex_order_obj( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rexqueue), act ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_order", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_order", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_rex_pool() const { @@ -663,7 +663,7 @@ class eosio_system_tester : public TESTER { data.resize( itr->value.size() ); memcpy( data.data(), itr->value.data(), data.size() ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_pool", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_pool", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_rex_return_pool() const { @@ -684,7 +684,7 @@ class eosio_system_tester : public TESTER { 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 ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_pool", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_rex_return_buckets() const { @@ -705,7 +705,7 @@ class eosio_system_tester : public TESTER { 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 ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_buckets", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } void setup_rex_accounts( const std::vector& accounts, @@ -793,7 +793,7 @@ class eosio_system_tester : public TESTER { asset get_balance( const account_name& act, symbol balance_symbol = symbol{CORE_SYM} ) { vector data = get_row_by_account( N(eosio.token), act, N(accounts), account_name(balance_symbol.to_symbol_code().value) ); - return data.empty() ? asset(0, balance_symbol) : token_abi_ser.binary_to_variant("account", data, abi_serializer_max_time)["balance"].as(); + return data.empty() ? asset(0, balance_symbol) : token_abi_ser.binary_to_variant("account", data, abi_serializer::create_yield_function(abi_serializer_max_time))["balance"].as(); } asset get_balance( std::string_view act, symbol balance_symbol = symbol{CORE_SYM} ) { @@ -802,7 +802,7 @@ class eosio_system_tester : public TESTER { fc::variant get_total_stake( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, act, N(userres), act ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "user_resources", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "user_resources", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_total_stake( std::string_view act ) { return get_total_stake( account_name(act) ); @@ -810,7 +810,7 @@ class eosio_system_tester : public TESTER { fc::variant get_voter_info( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(voters), act ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "voter_info", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "voter_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_voter_info( std::string_view act ) { return get_voter_info( account_name(act) ); @@ -818,7 +818,7 @@ class eosio_system_tester : public TESTER { fc::variant get_producer_info( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(producers), act ); - return abi_ser.binary_to_variant( "producer_info", data, abi_serializer_max_time ); + return abi_ser.binary_to_variant( "producer_info", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_producer_info( std::string_view act ) { return get_producer_info( account_name(act) ); @@ -826,7 +826,7 @@ class eosio_system_tester : public TESTER { fc::variant get_producer_info2( const account_name& act ) { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(producers2), act ); - return abi_ser.binary_to_variant( "producer_info2", data, abi_serializer_max_time ); + return abi_ser.binary_to_variant( "producer_info2", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_producer_info2( std::string_view act ) { return get_producer_info2( account_name(act) ); @@ -920,7 +920,7 @@ class eosio_system_tester : public TESTER { auto symb = eosio::chain::symbol::from_string(symbolname); auto symbol_code = symb.to_symbol_code().value; vector data = get_row_by_account( N(eosio.token), name(symbol_code), N(stat), account_name(symbol_code) ); - return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } asset get_token_supply() { @@ -934,22 +934,22 @@ class eosio_system_tester : public TESTER { fc::variant get_global_state() { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) ); if (data.empty()) std::cout << "\nData is empty\n" << std::endl; - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_global_state2() { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global2), N(global2) ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state2", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state2", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_global_state3() { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global3), N(global3) ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state3", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state3", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_refund_request( name account ) { vector data = get_row_by_account( config::system_account_name, account, N(refunds), account ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "refund_request", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "refund_request", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } abi_serializer initialize_multisig() { @@ -972,7 +972,7 @@ class eosio_system_tester : public TESTER { const auto& accnt = control->db().get( N(eosio.msig) ); abi_def msig_abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, msig_abi), true); - msig_abi_ser.set_abi(msig_abi, abi_serializer_max_time); + msig_abi_ser.set_abi(msig_abi, abi_serializer::create_yield_function(abi_serializer_max_time)); } return msig_abi_ser; } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 08497875b..dbbf46d49 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -133,7 +133,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(rammarket), account_name(symbol{SY(4,RAMCORE)}.value()) ); BOOST_REQUIRE( !data.empty() ); - return abi_ser.binary_to_variant("exchange_state", data, abi_serializer_max_time); + return abi_ser.binary_to_variant("exchange_state", data, abi_serializer::create_yield_function(abi_serializer_max_time)); }; { @@ -1738,7 +1738,7 @@ BOOST_AUTO_TEST_CASE(extreme_inflation) try { asset current_supply; { vector data = t.get_row_by_account( N(eosio.token), name(core_symbol.to_symbol_code().value), N(stat), account_name(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(); + current_supply = t.token_abi_ser.binary_to_variant("currency_stats", data, abi_serializer::create_yield_function(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)); @@ -2658,7 +2658,7 @@ BOOST_AUTO_TEST_CASE(votepay_transition2, * boost::unit_test::tolerance(1e-10)) const auto& accnt = t.control->db().get( config::system_account_name ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - t.abi_ser.set_abi(abi, eosio_system_tester::abi_serializer_max_time); + t.abi_ser.set_abi(abi, abi_serializer::create_yield_function(eosio_system_tester::abi_serializer_max_time)); } const asset net = old_core_from_string("80.0000"); const asset cpu = old_core_from_string("80.0000"); @@ -2732,7 +2732,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) action act; act.account = N(eosio.msig); act.name = name; - act.data = msig_abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); + act.data = msig_abi_ser.variant_to_binary( action_type_name, data, abi_serializer::create_yield_function(abi_serializer_max_time) ); return base_tester::push_action( std::move(act), (auth ? signer : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)).to_uint64_t() ); }; @@ -2771,7 +2771,7 @@ BOOST_FIXTURE_TEST_CASE(producers_upgrade_system_contract, eosio_system_tester) ) }) ); - abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer::create_yield_function(abi_serializer_max_time)); } BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() @@ -3514,7 +3514,7 @@ BOOST_FIXTURE_TEST_CASE( setparams, eosio_system_tester ) try { action act; act.account = N(eosio.msig); act.name = name; - act.data = msig_abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time ); + act.data = msig_abi_ser.variant_to_binary( action_type_name, data, abi_serializer::create_yield_function(abi_serializer_max_time) ); return base_tester::push_action( std::move(act), (auth ? signer : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111)).to_uint64_t() ); }; @@ -3550,7 +3550,7 @@ BOOST_FIXTURE_TEST_CASE( setparams, eosio_system_tester ) try { ) }) ); - abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer_max_time); + abi_serializer::from_variant(pretty_trx, trx, get_resolver(), abi_serializer::create_yield_function(abi_serializer_max_time)); } BOOST_REQUIRE_EQUAL(success(), push_action_msig( N(alice1111111), N(propose), mvo() @@ -5514,7 +5514,7 @@ BOOST_AUTO_TEST_CASE( setabi_bios ) try { validating_tester t( tempdir, true ); t.execute_setup_policy( setup_policy::full ); - abi_serializer abi_ser(fc::json::from_string( (const char*)contracts::bios_abi().data()).template as(), base_tester::abi_serializer_max_time); + abi_serializer abi_ser(fc::json::from_string( (const char*)contracts::bios_abi().data()).template as(), abi_serializer::create_yield_function(base_tester::abi_serializer_max_time)); t.set_code( config::system_account_name, contracts::bios_wasm() ); t.set_abi( config::system_account_name, contracts::bios_abi().data() ); t.create_account(N(eosio.token)); @@ -5522,8 +5522,8 @@ BOOST_AUTO_TEST_CASE( setabi_bios ) try { { auto res = t.get_row_by_account( config::system_account_name, config::system_account_name, N(abihash), N(eosio.token) ); _abi_hash abi_hash; - auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, base_tester::abi_serializer_max_time ); - abi_serializer::from_variant( abi_hash_var, abi_hash, t.get_resolver(), base_tester::abi_serializer_max_time); + auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer::create_yield_function(base_tester::abi_serializer_max_time) ); + abi_serializer::from_variant( abi_hash_var, abi_hash, t.get_resolver(), abi_serializer::create_yield_function(base_tester::abi_serializer_max_time)); auto abi = fc::raw::pack(fc::json::from_string( (const char*)contracts::token_abi().data()).template as()); auto result = fc::sha256::hash( (const char*)abi.data(), abi.size() ); @@ -5534,8 +5534,8 @@ BOOST_AUTO_TEST_CASE( setabi_bios ) try { { auto res = t.get_row_by_account( config::system_account_name, config::system_account_name, N(abihash), N(eosio.token) ); _abi_hash abi_hash; - auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, base_tester::abi_serializer_max_time ); - abi_serializer::from_variant( abi_hash_var, abi_hash, t.get_resolver(), base_tester::abi_serializer_max_time); + auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer::create_yield_function(base_tester::abi_serializer_max_time) ); + abi_serializer::from_variant( abi_hash_var, abi_hash, t.get_resolver(), abi_serializer::create_yield_function(base_tester::abi_serializer_max_time)); auto abi = fc::raw::pack(fc::json::from_string( (const char*)contracts::system_abi().data()).template as()); auto result = fc::sha256::hash( (const char*)abi.data(), abi.size() ); @@ -5548,8 +5548,8 @@ BOOST_FIXTURE_TEST_CASE( setabi, eosio_system_tester ) try { { auto res = get_row_by_account( config::system_account_name, config::system_account_name, N(abihash), N(eosio.token) ); _abi_hash abi_hash; - auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer_max_time ); - abi_serializer::from_variant( abi_hash_var, abi_hash, get_resolver(), abi_serializer_max_time); + auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer::create_yield_function(abi_serializer_max_time) ); + abi_serializer::from_variant( abi_hash_var, abi_hash, get_resolver(), abi_serializer::create_yield_function(abi_serializer_max_time)); auto abi = fc::raw::pack(fc::json::from_string( (const char*)contracts::token_abi().data()).template as()); auto result = fc::sha256::hash( (const char*)abi.data(), abi.size() ); @@ -5560,8 +5560,8 @@ BOOST_FIXTURE_TEST_CASE( setabi, eosio_system_tester ) try { { auto res = get_row_by_account( config::system_account_name, config::system_account_name, N(abihash), N(eosio.token) ); _abi_hash abi_hash; - auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer_max_time ); - abi_serializer::from_variant( abi_hash_var, abi_hash, get_resolver(), abi_serializer_max_time); + auto abi_hash_var = abi_ser.binary_to_variant( "abi_hash", res, abi_serializer::create_yield_function(abi_serializer_max_time) ); + abi_serializer::from_variant( abi_hash_var, abi_hash, get_resolver(), abi_serializer::create_yield_function(abi_serializer_max_time)); auto abi = fc::raw::pack(fc::json::from_string( (const char*)contracts::system_abi().data()).template as()); auto result = fc::sha256::hash( (const char*)abi.data(), abi.size() ); diff --git a/tests/eosio.token_tests.cpp b/tests/eosio.token_tests.cpp index 9a1d82193..23de001aa 100644 --- a/tests/eosio.token_tests.cpp +++ b/tests/eosio.token_tests.cpp @@ -33,7 +33,7 @@ class eosio_token_tester : public tester { const auto& accnt = control->db().get( N(eosio.token) ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer_max_time); + abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); } action_result push_action( const account_name& signer, const action_name &name, const variant_object &data ) { @@ -42,7 +42,7 @@ class eosio_token_tester : public tester { action act; act.account = N(eosio.token); act.name = name; - act.data = abi_ser.variant_to_binary( action_type_name, data,abi_serializer_max_time ); + act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer::create_yield_function(abi_serializer_max_time) ); return base_tester::push_action( std::move(act), signer.to_uint64_t() ); } @@ -52,7 +52,7 @@ class eosio_token_tester : public tester { auto symb = eosio::chain::symbol::from_string(symbolname); auto symbol_code = symb.to_symbol_code().value; vector data = get_row_by_account( N(eosio.token), name(symbol_code), N(stat), account_name(symbol_code) ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "currency_stats", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } fc::variant get_account( account_name acc, const string& symbolname) @@ -60,7 +60,7 @@ class eosio_token_tester : public tester { auto symb = eosio::chain::symbol::from_string(symbolname); auto symbol_code = symb.to_symbol_code().value; vector data = get_row_by_account( N(eosio.token), acc, N(accounts), account_name(symbol_code) ); - return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account", data, abi_serializer_max_time ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "account", data, abi_serializer::create_yield_function(abi_serializer_max_time) ); } action_result create( account_name issuer, diff --git a/tests/eosio.wrap_tests.cpp b/tests/eosio.wrap_tests.cpp index e7b7cb03e..1f462bb85 100644 --- a/tests/eosio.wrap_tests.cpp +++ b/tests/eosio.wrap_tests.cpp @@ -77,7 +77,7 @@ class eosio_wrap_tester : public tester { const auto& accnt = control->db().get( N(eosio.wrap) ); abi_def abi; BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi, abi_serializer_max_time); + abi_ser.set_abi(abi, abi_serializer::create_yield_function(abi_serializer_max_time)); while( control->pending_block_producer().to_string() == "eosio" ) { produce_block(); @@ -134,7 +134,7 @@ transaction eosio_wrap_tester::wrap_exec( account_name executer, const transacti transaction trx2; set_transaction_headers(trx2, expiration); action act; - abi_serializer::from_variant( act_obj, act, get_resolver(), abi_serializer_max_time ); + abi_serializer::from_variant( act_obj, act, get_resolver(), abi_serializer::create_yield_function(abi_serializer_max_time) ); trx2.actions.push_back( std::move(act) ); return trx2; } @@ -155,7 +155,7 @@ transaction eosio_wrap_tester::reqauth( account_name from, const vector Date: Wed, 27 May 2020 15:06:42 +0300 Subject: [PATCH 58/78] fixes #481 --- docs/01_key-concepts/02_ram.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index 63055a464..d1c782b1c 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -7,6 +7,6 @@ RAM is the memory, storage space, where the blockchain stores data. If your cont 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 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 block, 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. 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). \ No newline at end of file From d44e7e8048349dd378180fb8cc391116cf872fbf Mon Sep 17 00:00:00 2001 From: iamveritas Date: Wed, 12 Feb 2020 16:40:51 +0200 Subject: [PATCH 59/78] update links and clean up annotations --- contracts/eosio.system/include/eosio.system/native.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/native.hpp b/contracts/eosio.system/include/eosio.system/native.hpp index ca885347a..a0931cde2 100644 --- a/contracts/eosio.system/include/eosio.system/native.hpp +++ b/contracts/eosio.system/include/eosio.system/native.hpp @@ -127,7 +127,6 @@ namespace eosiosystem { using eosio::contract::contract; /** - * @{ * These actions map one-on-one with the ones defined in core layer of EOSIO, that's where their implementation * actually is done. * They are present here only so they can show up in the abi file and thus user can send them @@ -249,8 +248,6 @@ namespace eosiosystem { [[eosio::action]] void setcode( const name& account, uint8_t vmtype, uint8_t vmversion, const std::vector& code ) {} - /** @}*/ - using newaccount_action = eosio::action_wrapper<"newaccount"_n, &native::newaccount>; using updateauth_action = eosio::action_wrapper<"updateauth"_n, &native::updateauth>; using deleteauth_action = eosio::action_wrapper<"deleteauth"_n, &native::deleteauth>; From ec98a8a92e979d826b293ddbd9a0fddfe37e1bd8 Mon Sep 17 00:00:00 2001 From: iamveritas Date: Thu, 4 Jun 2020 13:12:02 +0300 Subject: [PATCH 60/78] fixes #491 --- docs/01_key-concepts/02_ram.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index d1c782b1c..afa832f81 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -3,10 +3,30 @@ content_title: RAM as resource link_text: RAM as resource --- -RAM is the memory, storage space, 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 is explained [here](https://developers.eos.io/manuals/eosio.cdt/latest/group__multiindex) and its usages [here](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index) or a `singleton`, with its definition found [here](https://developers.eos.io/manuals/eosio.cdt/latest/group__singleton/#singleton-table) and a sample of its usage [here](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton). +## What is RAM + +RAM is the memory, the storage space, 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` or a `singleton`. + +### Related documentation articles + +- Multi-index table [explainer documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/group__multiindex) + +- Multi-index table [how to documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index) + +- Singleton [reference documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/group__singleton/#singleton-table) + +- Singleton [how to documentation page](https://developers.eos.io/manuals/eosio.cdt/latest/how-to-guides/multi-index/how-to-define-a-singleton) + +## RAM High Performance 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 block, 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. 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 Importance + +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 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. + +- RAM is used in executing many actions sent to the blockchain; creating a new account action, 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). \ No newline at end of file From 3c5c876ea8d55d4109744bc57f1bf4fb89b3d3c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Wed, 17 Jun 2020 15:19:58 -0400 Subject: [PATCH 61/78] Fix compilation with CDT develop --- contracts/eosio.system/src/delegate_bandwidth.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/eosio.system/src/delegate_bandwidth.cpp b/contracts/eosio.system/src/delegate_bandwidth.cpp index d15a8202a..a64506c01 100644 --- a/contracts/eosio.system/src/delegate_bandwidth.cpp +++ b/contracts/eosio.system/src/delegate_bandwidth.cpp @@ -8,9 +8,6 @@ #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; From 5bbbc650af32e4207fce67aa68d2d27c9f1f268f Mon Sep 17 00:00:00 2001 From: Jeffrey Smith II Date: Mon, 29 Jun 2020 15:46:58 -0400 Subject: [PATCH 62/78] Add missing file to CMakeLists --- contracts/eosio.system/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index 3f9090846..a1642fa29 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -2,6 +2,7 @@ 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/name_bidding.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/native.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/producer_pay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp From 70c3b55fdec0d17835363fd905163b5f0c7aae04 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 25 Sep 2020 17:40:38 -0400 Subject: [PATCH 63/78] fix shell prompt and codeblocks on upgrading system contract --- .../01_upgrading-the-eosio.system-contract.md | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/docs/04_guides/01_upgrading-the-eosio.system-contract.md b/docs/04_guides/01_upgrading-the-eosio.system-contract.md index 51f493758..8196453f0 100644 --- a/docs/04_guides/01_upgrading-the-eosio.system-contract.md +++ b/docs/04_guides/01_upgrading-the-eosio.system-contract.md @@ -21,8 +21,10 @@ 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): +```sh +cleos get code -c original_system_contract.wast -a original_system_contract.abi eosio ``` -$ cleos get code -c original_system_contract.wast -a original_system_contract.abi eosio +```console code hash: cc0ffc30150a07c487d8247a484ce1caf9c95779521d8c230040c2cb0e2a3a60 saving wast to original_system_contract.wast saving abi to original_system_contract.abi @@ -30,13 +32,13 @@ 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 +```sh +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`): -``` +```json { "expiration": "2018-06-15T22:17:10", "ref_block_num": 4552, @@ -57,7 +59,7 @@ The first few lines of the generated file should be something similar to (except and the last few lines should be: -``` +```json } ], "transaction_extensions": [], @@ -76,8 +78,10 @@ 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: +```sh +diff upgrade_system_contract_official_trx.json upgrade_system_contract_trx.json ``` -$ diff upgrade_system_contract_official_trx.json upgrade_system_contract_trx.json +```json 2,4c2,4 < "expiration": "2018-06-15T22:17:10", < "ref_block_num": 4552, @@ -94,8 +98,10 @@ First, the block producer should collect all the necessary information. Let us a Then on a secure computer the producer can sign the transaction (the producer will need to paste in their private key when prompted): +```sh +cleos sign --chain-id d0242fb30b71b82df9966d10ff6d09e4f5eb6be7ba85fd78f796937f1959315e upgrade_system_contract_trx.json | tail -n 5 ``` -$ cleos sign --chain-id d0242fb30b71b82df9966d10ff6d09e4f5eb6be7ba85fd78f796937f1959315e upgrade_system_contract_trx.json | tail -n 5 +```json private key: "signatures": [ "SIG_K1_JzABB9gzDGwUHaRmox68UNcfxMVwMnEXqqS1MvtsyUX8KGTbsZ5aZQZjHD5vREQa5BkZ7ft8CceLBLAj8eZ5erZb9cHuy5" ], @@ -111,8 +117,10 @@ When the lead producer collects 15 producer signatures, the lead producer should 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: +```sh +cat upgrade_system_contract_official_trx_signed.json | tail -n 20 ``` -$ cat upgrade_system_contract_official_trx_signed.json | tail -n 20 +```json "transaction_extensions": [], "signatures": [ "SIG_K1_JzABB9gzDGwUHaRmox68UNcfxMVwMnEXqqS1MvtsyUX8KGTbsZ5aZQZjHD5vREQa5BkZ7ft8CceLBLAj8eZ5erZb9cHuy5", @@ -137,8 +145,10 @@ $ cat upgrade_system_contract_official_trx_signed.json | tail -n 20 8. Push the signed transaction to the blockchain: +```sh +cleos push transaction --skip-sign upgrade_system_contract_official_trx_signed.json ``` -$ cleos push transaction --skip-sign upgrade_system_contract_official_trx_signed.json +```json { "transaction_id": "202888b32e7a0f9de1b8483befac8118188c786380f6e62ced445f93fb2b1041", "processed": { @@ -157,7 +167,7 @@ $ cleos push transaction --skip-sign upgrade_system_contract_official_trx_signed If you get an error message like the following: -``` +```console 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. ``` @@ -166,7 +176,7 @@ That means that at least one of the signatures provided were bad. This may be be If you get an error message like the following: -``` +```console Error 3090002: irrelevant signature included Please remove the unnecessary signature from your transaction! ``` @@ -175,7 +185,7 @@ That means unnecessary signatures were included. If there are 21 active producer If you get an error message like the following: -``` +```console Error 3040006: Transaction Expiration Too Far Please decrease the expiration time of your transaction! ``` @@ -184,7 +194,7 @@ That means that the expiration time is more than 1 hour in the future and you ne If you get an error message like the following: -``` +```console Error 3040005: Expired Transaction Please increase the expiration time of your transaction! ``` @@ -193,12 +203,19 @@ That means the expiration time of the signed transaction has passed and this ent 9. Assuming the transaction successfully executes, everyone can then verify that the new contract is in place: +```sh +cleos get code -c new_system_contract.wast -a new_system_contract.abi eosio ``` -$ cleos get code -c new_system_contract.wast -a new_system_contract.abi eosio +```console 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 +``` + +```sh +diff original_system_contract.abi new_system_contract.abi +``` +```json 584,592d583 < },{ < "name": "deferred_trx_id", From 1faf34ea9b1abe3532f9ebdaca3258e8bd58f84e Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 25 Sep 2020 17:43:49 -0400 Subject: [PATCH 64/78] fix shell prompt and codeblocks on how-to create issue transfer token --- ...ow-to-create-issue-and-transfer-a-token.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md index ca08d5a59..0a2bf436e 100644 --- a/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md +++ b/docs/04_guides/05_how-to-create-issue-and-transfer-a-token.md @@ -7,16 +7,16 @@ link_text: How to create, issue and transfer a token Navigate to your contracts directory. -```text +```sh cd CONTRACTS_DIR ``` Pull the source -```text +```sh git clone https://github.com/EOSIO/eosio.contracts --branch master --single-branch ``` -```text +```sh cd eosio.contracts/contracts/eosio.token ``` @@ -41,7 +41,7 @@ cleos set contract eosio.token CONTRACTS_DIR/eosio.contracts/contracts/eosio.tok ``` Result should look similar to the one below: -```shell +```console Reading WASM from ... Publishing contract... executed transaction: 69c68b1bd5d61a0cc146b11e89e11f02527f24e4b240731c4003ad1dc0c87c2c 9696 bytes 6290 us @@ -57,7 +57,7 @@ cleos push action eosio.token create '[ "eosio", "1000000000.0000 SYS"]' -p eosi ``` Result should look similar to the one below: -```shell +```console executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles # eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} ``` @@ -69,7 +69,7 @@ cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"10000 ``` Result should look similar to the one below: -```shell +```console executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 120 bytes 1000 cycles # eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 SYS"} ``` @@ -79,12 +79,12 @@ This command created a new token `SYS` with a precision of 4 decimals and a maxi The issuer can issue new tokens to the issuer account in our case `eosio`. -```text +```sh cleos push action eosio.token issue '[ "eosio", "100.0000 SYS", "memo" ]' -p eosio@active ``` Result should look similar to the one below: -```shell +```console 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 ] @@ -99,7 +99,7 @@ cleos push action eosio.token transfer '[ "eosio", "bob", "25.0000 SYS", "m" ]' ``` Result should look similar to the one below: -```text +```console 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"} @@ -113,7 +113,7 @@ cleos get currency balance eosio.token bob SYS ``` Result: -```text +```console 25.00 SYS ``` @@ -124,6 +124,6 @@ cleos get currency balance eosio.token eosio SYS ``` Result: -```text +```console 75.00 SYS ``` \ No newline at end of file From 8fa6b79d532e05b34104d964a7871615caed9bc9 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 25 Sep 2020 18:14:53 -0400 Subject: [PATCH 65/78] fix shell prompt and codeblocks on how-to sign multisig --- ...-a-multisig-transaction-with-eosio.msig.md | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md index 9a20e7a1b..6014c9ba1 100644 --- a/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md +++ b/docs/04_guides/06_how-to-sign-a-multisig-transaction-with-eosio.msig.md @@ -12,16 +12,19 @@ link_text: How to sign a multisig transaction with eosio.msig - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. ### 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 - +```sh +cleos multisig propose test '[{"actor": "treasury", "permission": "active"}]' '[{"actor": "treasury", "permission": "active"}]' eosio.token issue '{"to": "tester", "quantity": "1000.0000 SYS", "memo": ""}' -p tester +``` +```console executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]... -```` +``` ### Another user reviews the transaction: -```` -$ cleos multisig review tester test +```sh +cleos multisig review tester test +``` +```json { "proposal_name": "test", "requested_approvals": [{ @@ -58,23 +61,25 @@ $ cleos multisig review tester test ] } } -```` +``` ### And then approves it: -```` -$ cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury - +```sh +cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury +``` +```console executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd95101b88d 256 bytes 108544 cycles # eosio.msig <= eosio.msig::approve {"proposer":"tester","proposal_name":"test","level":{"actor":"treasury","permission":"active"}} -```` +``` ### First user initiates execution: -```` -$ cleos multisig exec tester test -p tester - +```sh +cleos multisig exec tester test -p tester +``` +```console executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e56d6c2 248 bytes 109568 cycles # eosio.msig <= eosio.msig::exec {"proposer":"tester","proposal_name":"test","executer":"tester"} -```` +``` ## Cleos usage example for transferring tokens. @@ -86,16 +91,19 @@ executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e - keys to accounts 'treasury' and 'tester' imported into local wallet, the wallet is unlocked. ### 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 - +```sh +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 +``` +```console executed transaction: e26f3a3a7cba524a7b15a0b6c77c7daa73d3ba9bf84e83f9c2cdf27fcb183d61 336 bytes 107520 cycles # eosio.msig <= eosio.msig::propose {"proposer":"tester","proposal_name":"test","requested":[{"actor":"treasury","permission":"active"}]... -```` +``` ### Another user reviews the transaction: -```` -$ cleos multisig review tester test +```sh +cleos multisig review tester test +``` +```json { "proposal_name": "test", "requested_approvals": [{ @@ -133,42 +141,48 @@ $ cleos multisig review tester test ] } } -```` +``` ### And then approves it: -```` -$ cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury - +```sh +cleos multisig approve tester test '{"actor": "treasury", "permission": "active"}' -p treasury +``` +```console executed transaction: 475970a4b0016368d0503d1ce01577376f91f5a5ba63dd4353683bd95101b88d 256 bytes 108544 cycles # 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 -```` -$ cleos get account tester +```sh +cleos get account tester +``` +```console ... SYS balances: liquid: 1.0487 SYS staked: 2.0000 SYS unstaking: 0.0000 SYS total: 4.0487 SYS -```` +``` ### First user initiates execution of proposed transaction: -```` -$ cleos multisig exec tester test -p tester - +```sh +cleos multisig exec tester test -p tester +``` +```console executed transaction: 64e5eaceb77362694055f572ae35876111e87b637a55250de315b1b55e56d6c2 248 bytes 109568 cycles # 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 -```` -$ cleos get account tester +```sh +cleos get account tester +``` +```console ... SYS balances: liquid: 2.0487 SYS staked: 2.0000 SYS unstaking: 0.0000 SYS total: 4.0487 SYS -```` \ No newline at end of file +``` From da8ca230876e9a57482a8f56455eedc5ca2c6d66 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 25 Sep 2020 18:15:53 -0400 Subject: [PATCH 66/78] fix shell prompt and codeblocks on how-to vote --- docs/04_guides/04_how-to-vote.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/04_guides/04_how-to-vote.md b/docs/04_guides/04_how-to-vote.md index 0141d1568..ee9e1f961 100644 --- a/docs/04_guides/04_how-to-vote.md +++ b/docs/04_guides/04_how-to-vote.md @@ -29,7 +29,7 @@ cleos system voteproducer prods eosiotestts2 blockproducer1 blockproducer2 You should see something like below: -```bash +```console executed transaction: 2d8b58f7387aef52a1746d7a22d304bbbe0304481d7751fc4a50b619df62676d 128 bytes 374 us # eosio <= eosio::voteproducer {"voter":"eosiotestts2","proxy":"","producers":["blockproducer1","blockproducer2"]} ``` \ No newline at end of file From 8cd26a88c05101a986905b139e4c01a5dc047e31 Mon Sep 17 00:00:00 2001 From: Luis Paris Date: Fri, 25 Sep 2020 18:34:05 -0400 Subject: [PATCH 67/78] fix shell prompt and codeblocks on how-to use eosio wrap --- docs/04_guides/07_how-to-use-eosio.wrap.md | 214 +++++++++++++++------ 1 file changed, 154 insertions(+), 60 deletions(-) diff --git a/docs/04_guides/07_how-to-use-eosio.wrap.md b/docs/04_guides/07_how-to-use-eosio.wrap.md index 347be4e2c..807441c28 100644 --- a/docs/04_guides/07_how-to-use-eosio.wrap.md +++ b/docs/04_guides/07_how-to-use-eosio.wrap.md @@ -24,11 +24,17 @@ A simple way to generate a transaction to create a new account is to use the `cl Three unsigned transactions will be generated using cleos and then the actions within those transactions will be appropriately stitched together into a single transaction which will later be proposed using the eosio.msig contract. First, generate a transaction to capture the necessary actions involved in creating a new account: +```sh +cleos system newaccount -s -j -d --transfer --stake-net "1.000 SYS" --stake-cpu "1.000 SYS" --buy-ram-kbytes 50 eosio eosio.wrap EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json ``` -$ cleos system newaccount -s -j -d --transfer --stake-net "1.000 SYS" --stake-cpu "1.000 SYS" --buy-ram-kbytes 50 eosio eosio.wrap EOS8MMUW11TAdTDxqdSwSqJodefSoZbFhcprndomgLi9MeR2o8MT4 > generated_account_creation_trx.json +```console 726964ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea305500c80000"} arg: {"code":"eosio","action":"buyrambytes","args":{"payer":"eosio","receiver":"eosio.wrap","bytes":51200}} 726967ms thread-0 main.cpp:429 create_action ] result: {"binargs":"0000000000ea305500004d1a03ea3055102700000000000004535953000000001027000000000000045359530000000001"} arg: {"code":"eosio","action":"delegatebw","args":{"from":"eosio","receiver":"eosio.wrap","stake_net_quantity":"1.0000 SYS","stake_cpu_quantity":"1.0000 SYS","transfer":true}} -$ cat generated_account_creation_trx.json +``` +```sh +cat generated_account_creation_trx.json +``` +```json { "expiration": "2018-06-29T17:11:36", "ref_block_num": 16349, @@ -71,12 +77,15 @@ $ cat generated_account_creation_trx.json "context_free_data": [] } ``` + Adjust the amount of delegated tokens and the amount of RAM bytes to gift as necessary. The actual public key used is not important since that data is only encoded into the `eosio::newaccount` action which will be replaced soon anyway. Second, create a file (e.g. newaccount_payload.json) with the JSON payload for the real `eosio::newaccount` action. It should look like: +```sh +cat newaccount_payload.json ``` -$ cat newaccount_payload.json +```json { "creator": "eosio", "name": "eosio.wrap", @@ -102,9 +111,11 @@ $ cat newaccount_payload.json ``` Third, generate a transaction containing the actual `eosio::newaccount` action that will be used in the final transaction: +```sh +cleos push action -s -j -d eosio newaccount newaccount_payload.json -p eosio > generated_newaccount_trx.json +cat generated_newaccount_trx.json ``` -$ cleos push action -s -j -d eosio newaccount newaccount_payload.json -p eosio > generated_newaccount_trx.json -$ cat generated_newaccount_trx.json +```json { "expiration": "2018-06-29T17:11:36", "ref_block_num": 16349, @@ -131,9 +142,11 @@ $ cat generated_newaccount_trx.json ``` Fourth, generate a transaction containing the `eosio::setpriv` action which will make the `eosio.wrap` account privileged: +```sh +cleos push action -s -j -d eosio setpriv '{"account": "eosio.wrap", "is_priv": 1}' -p eosio > generated_setpriv_trx.json +cat generated_setpriv_trx.json ``` -$ cleos push action -s -j -d eosio setpriv '{"account": "eosio.wrap", "is_priv": 1}' -p eosio > generated_setpriv_trx.json -$ cat generated_setpriv_trx.json +```json { "expiration": "2018-06-29T17:11:36", "ref_block_num": 16349, @@ -160,8 +173,10 @@ $ cat generated_setpriv_trx.json ``` Next, the action JSONs of the previously generated transactions will be used to construct a unified transaction which will eventually be proposed with the eosio.msig contract. A good way to get started is to make a copy of the generated_newaccount_trx.json file (call the copied file create_wrap_account_trx.json) and edit the first three fields so it looks something like the following: +```sh +cat create_wrap_account_trx.json ``` -$ cat create_wrap_account_trx.json +```json { "expiration": "2018-07-06T12:00:00", "ref_block_num": 0, @@ -190,8 +205,10 @@ $ cat create_wrap_account_trx.json The `ref_block_num` and `ref_block_prefix` values were set to 0. The proposed transaction does not need to have a valid TaPoS reference block because it will be reset anyway when scheduled as a deferred transaction during the `eosio.msig::exec` action. The `expiration` field, which was the only other field that was changed, will also be reset when the proposed transaction is scheduled as a deferred transaction during `eosio.msig::exec`. However, this field actually does matter during the propose-approve-exec lifecycle of the proposed transaction. If the present time passes the time in the `expiration` field of the proposed transaction, it will not be possible to execute the proposed transaction even if all necessary approvals are gathered. Therefore, it is important to set the expiration time to some point well enough in the future to give all necessary approvers enough time to review and approve the proposed transaction, but it is otherwise arbitrary. Generally, for reviewing/validation purposes it is important that all potential approvers of the transaction (i.e. the block producers) choose the exact same `expiration` time so that there is not any discrepancy in bytes of the serialized transaction if it was to later be included in payload data of some other action. Then, all but the first action JSON object of generated_account_creation_trx.json should be appended to the `actions` array of create_wrap_account_trx.json, and then the single action JSON object of generated_setpriv_trx.json should be appended to the `actions` array of create_wrap_account_trx.json. The final result is a create_wrap_account_trx.json file that looks like the following: +```sh +cat create_wrap_account_trx.json ``` -$ cat create_wrap_account_trx.json +```json { "expiration": "2018-07-06T12:00:00", "ref_block_num": 0, @@ -251,8 +268,10 @@ It will be useful to have a JSON of the active permissions of each of the active This guide will assume that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. In that case, create a file producer_permissions.json with the content shown in the command below: +```sh +cat producer_permissions.json ``` -$ cat producer_permissions.json +```json [ {"actor": "blkproducera", "permission": "active"}, {"actor": "blkproducerb", "permission": "active"}, @@ -287,8 +306,10 @@ The approvers are typically going to be the active block producers of the chain, The guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. The lead block producer (`blkproducera`) should propose the transaction stored in create_wrap_account_trx.json: +```sh +cleos multisig propose_trx createwrap producer_permissions.json create_wrap_account_trx.json blkproducera ``` -$ cleos multisig propose_trx createwrap producer_permissions.json create_wrap_account_trx.json blkproducera +```console executed transaction: bf6aaa06b40e2a35491525cb11431efd2b5ac94e4a7a9c693c5bf0cfed942393 744 bytes 772 us # eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"createwrap","requested":[{"actor":"blkproducera","permis... warning: transaction executed locally, but may not be confirmed by the network yet @@ -299,9 +320,11 @@ warning: transaction executed locally, but may not be confirmed by the network y Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. The proposed transaction can be reviewed using the `cleos multisig review` command: +```sh +cleos multisig review blkproducera createwrap > create_wrap_account_trx_to_review.json +head -n 30 create_wrap_account_trx_to_review.json ``` -$ cleos multisig review blkproducera createwrap > create_wrap_account_trx_to_review.json -$ head -n 30 create_wrap_account_trx_to_review.json +```json { "proposal_name": "createwrap", "packed_transaction": "c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100", @@ -335,19 +358,29 @@ $ head -n 30 create_wrap_account_trx_to_review.json ``` The approvers should go through the full human-readable transaction output and make sure everything looks fine. But they can also use tools to automatically compare the proposed transaction to the one they generated to make sure there are absolutely no differences: +```sh +cleos multisig propose_trx -j -s -d createwrap '[]' create_wrap_account_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_create_wrap_trx_serialized.hex +cat expected_create_wrap_trx_serialized.hex ``` -$ cleos multisig propose_trx -j -s -d createwrap '[]' create_wrap_account_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_create_wrap_trx_serialized.hex -$ cat expected_create_wrap_trx_serialized.hex +```console c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 -$ cat create_wrap_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_create_wrap_trx_serialized.hex -$ cat proposed_create_wrap_trx_serialized.hex +``` +```sh +cat create_wrap_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_create_wrap_trx_serialized.hex +cat proposed_create_wrap_trx_serialized.hex +``` +```console c0593f5b00000000000000000000040000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232420000000000ea305500004d1a03ea30550100000000010000000000ea305500000000a8ed32320100000100000000010000000000ea305500000000a8ed32320100000000000000ea305500b0cafe4873bd3e010000000000ea305500000000a8ed3232140000000000ea305500004d1a03ea3055002800000000000000ea305500003f2a1ba6a24a010000000000ea305500000000a8ed3232310000000000ea305500004d1a03ea30551027000000000000045359530000000010270000000000000453595300000000010000000000ea305500000060bb5bb3c2010000000000ea305500000000a8ed32320900004d1a03ea30550100 -$ diff expected_create_wrap_trx_serialized.hex proposed_create_wrap_trx_serialized.hex +``` +```sh +diff expected_create_wrap_trx_serialized.hex proposed_create_wrap_trx_serialized.hex ``` When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +```sh +cleos multisig approve blkproducera createwrap '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb ``` -$ cleos multisig approve blkproducera createwrap '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +```console executed transaction: 03a907e2a3192aac0cd040c73db8273c9da7696dc7960de22b1a479ae5ee9f23 128 bytes 472 us # eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"createwrap","level":{"actor":"blkproducerb","permission"... warning: transaction executed locally, but may not be confirmed by the network yet @@ -357,16 +390,20 @@ warning: transaction executed locally, but may not be confirmed by the network y When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +```sh +cleos multisig exec blkproducera createwrap blkproducera ``` -$ cleos multisig exec blkproducera createwrap blkproducera +```console executed transaction: 7ecc183b99915cc411f96dde7c35c3fe0df6e732507f272af3a039b706482e5a 160 bytes 850 us # eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"createwrap","executer":"blkproducera"} warning: transaction executed locally, but may not be confirmed by the network yet ``` Anyone can now verify that the `eosio.wrap` was created: +```sh +cleos get account eosio.wrap ``` -$ cleos get account eosio.wrap +```console privileged: true permissions: owner 1: 1 eosio@active, @@ -389,7 +426,6 @@ cpu bandwidth: limit: 460.8 ms producers: - ``` ## 1.2 Deploy the eosio.wrap contract @@ -399,12 +435,18 @@ producers: The transaction to deploy the contract to the `eosio.wrap` account will need to be proposed to get the necessary approvals from active block producers before executing it. This transaction needs to first be generated and stored as JSON into a file so that it can be used in the cleos command to propose the transaction to the eosio.msig contract. The easy way to generate this transaction is using cleos: +```sh +cleos set contract -s -j -d eosio.wrap contracts/eosio.wrap/ > deploy_wrap_contract_trx.json ``` -$ cleos set contract -s -j -d eosio.wrap contracts/eosio.wrap/ > deploy_wrap_contract_trx.json +```console Reading WAST/WASM from contracts/eosio.wrap/eosio.wrap.wasm... Using already assembled WASM... Publishing contract... -$ cat deploy_wrap_contract_trx.json +``` +```sh +cat deploy_wrap_contract_trx.json +``` +```json { "expiration": "2018-06-29T19:55:26", "ref_block_num": 18544, @@ -440,8 +482,10 @@ $ cat deploy_wrap_contract_trx.json ``` Once again, as described in sub-section 2.1.1, edit the values of the `ref_block_num` and `ref_block_prefix` fields to be 0 and edit the time of the `expiration` field to some point in the future that provides enough time to approve and execute the proposed transaction. After editing deploy_wrap_contract_trx.json the first few lines of it may look something like the following: +```sh +head -n 9 deploy_wrap_contract_trx.json ``` -$ head -n 9 deploy_wrap_contract_trx.json +```json { "expiration": "2018-07-06T12:00:00", "ref_block_num": 0, @@ -464,8 +508,10 @@ The approvers are typically going to be the active block producers of the chain, This guide will assume that `blkproducera` was chosen as the lead block producer to propose the transaction. The lead block producer (`blkproducera`) should propose the transaction stored in deploy_wrap_contract_trx.json: +```sh +cleos multisig propose_trx deploywrap producer_permissions.json deploy_wrap_contract_trx.json blkproducera ``` -$ cleos multisig propose_trx deploywrap producer_permissions.json deploy_wrap_contract_trx.json blkproducera +```console executed transaction: 9e50dd40eba25583a657ee8114986a921d413b917002c8fb2d02e2d670f720a8 4312 bytes 871 us # eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"deploywrap","requested":[{"actor":"blkproducera","permis... warning: transaction executed locally, but may not be confirmed by the network yet @@ -476,9 +522,11 @@ warning: transaction executed locally, but may not be confirmed by the network y Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. The proposed transaction can be reviewed using the `cleos multisig review` command: +```sh +cleos multisig review blkproducera deploywrap > deploy_wrap_contract_trx_to_review.json +cat deploy_wrap_contract_trx_to_review.json ``` -$ cleos multisig review blkproducera deploywrap > deploy_wrap_contract_trx_to_review.json -$ cat deploy_wrap_contract_trx_to_review.json +```json { "proposal_name": "deploywrap", "packed_transaction": "c0593f5b00000000000000000000020000000000ea305500000040258ab2c20100004d1a03ea305500000000a8ed3232d41800004d1a03ea30550000c8180061736d01000000013e0c60017f006000017e60027e7e0060017e006000017f60027f7f017f60027f7f0060037f7f7f017f60057f7e7f7f7f0060000060037e7e7e0060017f017f029d010803656e7610616374696f6e5f646174615f73697a65000403656e760c63757272656e745f74696d65000103656e760c656f73696f5f617373657274000603656e76066d656d637079000703656e7610726561645f616374696f6e5f64617461000503656e760c726571756972655f61757468000303656e760d726571756972655f6175746832000203656e760d73656e645f64656665727265640008030f0e0505050400000a05070b050b000904050170010202050301000107c7010b066d656d6f72790200165f5a6571524b3131636865636b73756d32353653315f0008165f5a6571524b3131636865636b73756d31363053315f0009165f5a6e65524b3131636865636b73756d31363053315f000a036e6f77000b305f5a4e35656f73696f3132726571756972655f6175746845524b4e535f31367065726d697373696f6e5f6c6576656c45000c155f5a4e35656f73696f347375646f34657865634576000d056170706c79000e066d656d636d700010066d616c6c6f630011046672656500140908010041000b02150d0a9a130e0b002000200141201010450b0b002000200141201010450b0d0020002001412010104100470b0a00100142c0843d80a70b0e002000290300200029030810060b9e0102017e027f410028020441206b2202210341002002360204200029030010050240024010002200418104490d002000101121020c010b410020022000410f6a4170716b22023602040b2002200010041a200041074b41101002200341186a2002410810031a2003290318100520032903182101200310013703002003200137030820032003290318200241086a2000410010074100200341206a3602040bfd0403027f047e017f4100410028020441206b220936020442002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b024020072002520d0042002106423b2105413021044200210703400240024002400240024020064204560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b200720015141c00010020b0240024020012000510d0042002106423b2105412021044200210703400240024002400240024020064206560d0020042c00002203419f7f6a41ff017141194b0d01200341a5016a21030c020b420021082006420b580d020c030b200341d0016a41002003414f6a41ff01714105491b21030b2003ad42388642388721080b2008421f83200542ffffffff0f838621080b200441016a2104200642017c2106200820078421072005427b7c2205427a520d000b20072002520d010b20092000370318200242808080808080a0aad700520d00200941003602142009410136021020092009290310370208200941186a200941086a100f1a0b4100200941206a3602040b8c0101047f4100280204220521042001280204210220012802002101024010002203450d00024020034180044d0d00200310112205200310041a200510140c010b410020052003410f6a4170716b22053602042005200310041a0b200020024101756a210302402002410171450d00200328020020016a28020021010b200320011100004100200436020441010b4901037f4100210502402002450d000240034020002d0000220320012d00002204470d01200141016a2101200041016a21002002417f6a22020d000c020b0b200320046b21050b20050b0900418001200010120bcd04010c7f02402001450d00024020002802c041220d0d004110210d200041c0c1006a41103602000b200141086a200141046a41077122026b200120021b210202400240024020002802c441220a200d4f0d002000200a410c6c6a4180c0006a21010240200a0d0020004184c0006a220d2802000d0020014180c000360200200d20003602000b200241046a210a034002402001280208220d200a6a20012802004b0d002001280204200d6a220d200d28020041808080807871200272360200200141086a22012001280200200a6a360200200d200d28020041808080807872360200200d41046a22010d030b2000101322010d000b0b41fcffffff0720026b2104200041c8c1006a210b200041c0c1006a210c20002802c8412203210d03402000200d410c6c6a22014188c0006a28020020014180c0006a22052802004641d0c200100220014184c0006a280200220641046a210d0340200620052802006a2107200d417c6a2208280200220941ffffffff07712101024020094100480d000240200120024f0d000340200d20016a220a20074f0d01200a280200220a4100480d012001200a41ffffffff07716a41046a22012002490d000b0b20082001200220012002491b200941808080807871723602000240200120024d0d00200d20026a200420016a41ffffffff07713602000b200120024f0d040b200d20016a41046a220d2007490d000b41002101200b4100200b28020041016a220d200d200c280200461b220d360200200d2003470d000b0b20010f0b2008200828020041808080807872360200200d0f0b41000b870501087f20002802c44121010240024041002d00a643450d0041002802a84321070c010b3f002107410041013a00a6434100200741107422073602a8430b200721030240024002400240200741ffff036a41107622023f0022084d0d00200220086b40001a4100210820023f00470d0141002802a84321030b41002108410020033602a84320074100480d0020002001410c6c6a210220074180800441808008200741ffff037122084181f8034922061b6a2008200741ffff077120061b6b20076b2107024041002d00a6430d003f002103410041013a00a6434100200341107422033602a8430b20024180c0006a210220074100480d01200321060240200741076a417871220520036a41ffff036a41107622083f0022044d0d00200820046b40001a20083f00470d0241002802a84321060b4100200620056a3602a8432003417f460d0120002001410c6c6a22014184c0006a2802002206200228020022086a2003460d020240200820014188c0006a22052802002201460d00200620016a2206200628020041808080807871417c20016b20086a72360200200520022802003602002006200628020041ffffffff07713602000b200041c4c1006a2202200228020041016a220236020020002002410c6c6a22004184c0006a200336020020004180c0006a220820073602000b20080f0b02402002280200220820002001410c6c6a22034188c0006a22012802002207460d0020034184c0006a28020020076a2203200328020041808080807871417c20076b20086a72360200200120022802003602002003200328020041ffffffff07713602000b2000200041c4c1006a220728020041016a22033602c0412007200336020041000f0b2002200820076a36020020020b7b01037f024002402000450d0041002802c04222024101480d004180c10021032002410c6c4180c1006a21010340200341046a2802002202450d010240200241046a20004b0d00200220032802006a20004b0d030b2003410c6a22032001490d000b0b0f0b2000417c6a2203200328020041ffffffff07713602000b0300000b0bcf01060041040b04b04900000041100b0572656164000041200b086f6e6572726f72000041300b06656f73696f000041c0000b406f6e6572726f7220616374696f6e277320617265206f6e6c792076616c69642066726f6d207468652022656f73696f222073797374656d206163636f756e74000041d0c2000b566d616c6c6f635f66726f6d5f6672656564207761732064657369676e656420746f206f6e6c792062652063616c6c6564206166746572205f686561702077617320636f6d706c6574656c7920616c6c6f6361746564000000000000ea305500000000b863b2c20100004d1a03ea305500000000a8ed3232e90400004d1a03ea3055df040e656f73696f3a3a6162692f312e30030c6163636f756e745f6e616d65046e616d650f7065726d697373696f6e5f6e616d65046e616d650b616374696f6e5f6e616d65046e616d6506107065726d697373696f6e5f6c6576656c0002056163746f720c6163636f756e745f6e616d650a7065726d697373696f6e0f7065726d697373696f6e5f6e616d6506616374696f6e0004076163636f756e740c6163636f756e745f6e616d65046e616d650b616374696f6e5f6e616d650d617574686f72697a6174696f6e127065726d697373696f6e5f6c6576656c5b5d0464617461056279746573127472616e73616374696f6e5f68656164657200060a65787069726174696f6e0e74696d655f706f696e745f7365630d7265665f626c6f636b5f6e756d0675696e743136107265665f626c6f636b5f7072656669780675696e743332136d61785f6e65745f75736167655f776f7264730976617275696e743332106d61785f6370755f75736167655f6d730575696e74380964656c61795f7365630976617275696e74333209657874656e73696f6e000204747970650675696e74313604646174610562797465730b7472616e73616374696f6e127472616e73616374696f6e5f6865616465720314636f6e746578745f667265655f616374696f6e7308616374696f6e5b5d07616374696f6e7308616374696f6e5b5d167472616e73616374696f6e5f657874656e73696f6e730b657874656e73696f6e5b5d046578656300020865786563757465720c6163636f756e745f6e616d65037472780b7472616e73616374696f6e0100000000008054570465786563000000000000", @@ -528,19 +576,29 @@ $ cat deploy_wrap_contract_trx_to_review.json Each approver should be able to see that the proposed transaction is setting the code and ABI of the `eosio.wrap` contract. But the data is just hex data and therefore not very meaningful to the approver. And considering that `eosio.wrap` at this point should be a privileged contract, it would be very dangerous for block producers to just allow a contract to be deployed to a privileged account without knowing exactly which WebAssembly code they are deploying and also auditing the source code that generated that WebAssembly code to ensure it is safe to deploy. This guide assumes that each approver has already audited the source code of the contract to be deployed and has already compiled that code to generate the WebAssembly code that should be byte-for-byte identical to the code that every other approver following the same process should have generated. The guide also assumes that this generated code and its associated ABI were provided in the steps in sub-section 2.2.1 that generated the transaction in the deploy_wrap_contract_trx.json file. It then becomes quite simple to verify that the proposed transaction is identical to the one the potential approver could have proposed with the code and ABI that they already audited: +```sh +cleos multisig propose_trx -j -s -d deploywrap '[]' deploy_wrap_contract_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_deploy_wrap_trx_serialized.hex +cat expected_deploy_wrap_trx_serialized.hex | cut -c -50 ``` -$ cleos multisig propose_trx -j -s -d deploywrap '[]' deploy_wrap_contract_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_deploy_wrap_trx_serialized.hex -$ cat expected_deploy_wrap_trx_serialized.hex | cut -c -50 +```console c0593f5b00000000000000000000020000000000ea30550000 -$ cat deploy_wrap_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_deploy_wrap_trx_serialized.hex -$ cat proposed_deploy_wrap_trx_serialized.hex | cut -c -50 +``` +```sh +cat deploy_wrap_account_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_deploy_wrap_trx_serialized.hex +cat proposed_deploy_wrap_trx_serialized.hex | cut -c -50 +``` +```console c0593f5b00000000000000000000020000000000ea30550000 -$ diff expected_deploy_wrap_trx_serialized.hex proposed_deploy_wrap_trx_serialized.hex +``` +```sh +diff expected_deploy_wrap_trx_serialized.hex proposed_deploy_wrap_trx_serialized.hex ``` When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +```sh +cleos multisig approve blkproducera deploywrap '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb ``` -$ cleos multisig approve blkproducera deploywrap '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +```console executed transaction: d1e424e05ee4d96eb079fcd5190dd0bf35eca8c27dd7231b59df8e464881abfd 128 bytes 483 us # eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"deploywrap","level":{"actor":"blkproducerb","permission"... warning: transaction executed locally, but may not be confirmed by the network yet @@ -550,19 +608,27 @@ warning: transaction executed locally, but may not be confirmed by the network y When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +```sh +cleos multisig exec blkproducera deploywrap blkproducera ``` -$ cleos multisig exec blkproducera deploywrap blkproducera +```console executed transaction: e8da14c6f1fdc3255b5413adccfd0d89b18f832a4cc18c4324ea2beec6abd483 160 bytes 1877 us # eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"deploywrap","executer":"blkproducera"} ``` Anyone can now verify that the `eosio.wrap` contract was deployed correctly. +```sh +cleos get code -a retrieved-eosio.wrap.abi eosio.wrap ``` -$ cleos get code -a retrieved-eosio.wrap.abi eosio.wrap +```console code hash: 1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c saving abi to retrieved-eosio.wrap.abi -$ sha256sum contracts/eosio.wrap/eosio.wrap.wasm +``` +```sh +sha256sum contracts/eosio.wrap/eosio.wrap.wasm +``` +```console 1b3456a5eca28bcaca7a2a3360fbb2a72b9772a416c8e11a303bcb26bfe3263c contracts/eosio.wrap/eosio.wrap.wasm ``` @@ -577,8 +643,10 @@ This example will demonstrate how to use the deployed eosio.wrap contract togeth This guide assumes that there are 21 active block producers on the chain with account names: `blkproducera`, `blkproducerb`, ..., `blkproduceru`. Block producer `blkproducera` will act as the lead block producer handling the proposal of the transaction. The producer permissions will later come in handy when proposing a transaction that must be approved by a supermajority of the producers. So a file producer_permissions.json containing those permission (see contents below) should be created to be used later in this guide: +```sh +cat producer_permissions.json ``` -$ cat producer_permissions.json +```json [ {"actor": "blkproducera", "permission": "active"}, {"actor": "blkproducerb", "permission": "active"}, @@ -609,7 +677,7 @@ $ cat producer_permissions.json The goal of this example is for the block producers to change the owner permission of the account `alice`. The initial status of the `alice` account might be: -``` +```console permissions: owner 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV @@ -636,13 +704,15 @@ producers: Assume that none of the block producers know the private key corresponding to the public key `EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV` which, as can be seen above, is initially securing access to the `alice` account. The first step is to generate the transaction changing the owner permission of the `alice` account as if `alice` is authorizing the change: -``` -$ cleos set account permission -s -j -d alice owner '{"threshold": 1, "accounts": [{"permission": {"actor": "eosio", "permission": "active"}, "weight": 1}]}' > update_alice_owner_trx.json +```sh +cleos set account permission -s -j -d alice owner '{"threshold": 1, "accounts": [{"permission": {"actor": "eosio", "permission": "active"}, "weight": 1}]}' > update_alice_owner_trx.json ``` Then modify update_alice_owner_trx.json so that the values for the `ref_block_num` and `ref_block_prefix` fields are both 0 and the value of the `expiration` field is `"1970-01-01T00:00:00"`: +```sh +cat update_alice_owner_trx.json ``` -$ cat update_alice_owner_trx.json +```console { "expiration": "1970-01-01T00:00:00", "ref_block_num": 0, @@ -670,13 +740,15 @@ $ cat update_alice_owner_trx.json The next step is to generate the transaction containing the `eosio.wrap::exec` action. This action will contain the transaction in update_alice_owner_trx.json as part of its action payload data. -``` -$ cleos wrap exec -s -j -d blkproducera update_alice_owner_trx.json > wrap_update_alice_owner_trx.json +```sh +cleos wrap exec -s -j -d blkproducera update_alice_owner_trx.json > wrap_update_alice_owner_trx.json ``` Once again modify wrap_update_alice_owner_trx.json so that the value for the `ref_block_num` and `ref_block_prefix` fields are both 0. However, instead of changing the value of the expiration field to `"1970-01-01T00:00:00"`, it should be changed to a time that is far enough in the future to allow enough time for the proposed transaction to be approved and executed. +```sh +cat wrap_update_alice_owner_trx.json ``` -$ cat wrap_update_alice_owner_trx.json +```json { "expiration": "2018-07-06T12:00:00", "ref_block_num": 0, @@ -708,16 +780,20 @@ $ cat wrap_update_alice_owner_trx.json If the `cleos wrap` command is not available, there is an alternative way to generate the above transaction. There is no need to continue reading the remaining of sub-section 3.1.1 if the wrap_update_alice_owner_trx.json file was already generated with content similar to the above using the `cleos wrap exec` sub-command method. First the hex encoding of the binary serialization of the transaction in update_alice_owner_trx.json must be obtained. One way of obtaining this data is through the following command: +```sh +cleos multisig propose_trx -s -j -d nothing '[]' update_alice_owner_trx.json nothing | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > update_alice_owner_trx_serialized.hex +cat update_alice_owner_trx_serialized.hex ``` -$ cleos multisig propose_trx -s -j -d nothing '[]' update_alice_owner_trx.json nothing | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > update_alice_owner_trx_serialized.hex -$ cat update_alice_owner_trx_serialized.hex +```console 0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed323201000000 ``` Then generate the template for the transaction containing the `eosio.wrap::exec` action: +```sh +cleos push action -s -j -d eosio.wrap exec '{"executer": "blkproducera", "trx": ""}' > wrap_update_alice_owner_trx.json +cat wrap_update_alice_owner_trx.json ``` -$ cleos push action -s -j -d eosio.wrap exec '{"executer": "blkproducera", "trx": ""}' > wrap_update_alice_owner_trx.json -$ cat wrap_update_alice_owner_trx.json +```json { "expiration": "2018-06-29T23:34:01", "ref_block_num": 23708, @@ -748,8 +824,10 @@ Then modify the transaction in wrap_update_alice_owner_trx.json as follows: ### 2.1.2 Propose the transaction to change the owner permission of an account The lead block producer (`blkproducera`) should propose the transaction stored in wrap_update_alice_owner_trx.json: +```sh +cleos multisig propose_trx updatealice producer_permissions.json wrap_update_alice_owner_trx.json blkproducera ``` -$ cleos multisig propose_trx updatealice producer_permissions.json wrap_update_alice_owner_trx.json blkproducera +```console executed transaction: 10474f52c9e3fc8e729469a577cd2fc9e4330e25b3fd402fc738ddde26605c13 624 bytes 782 us # eosio.msig <= eosio.msig::propose {"proposer":"blkproducera","proposal_name":"updatealice","requested":[{"actor":"blkproducera","permi... warning: transaction executed locally, but may not be confirmed by the network yet @@ -758,9 +836,11 @@ warning: transaction executed locally, but may not be confirmed by the network y ### 2.1.3 Review and approve the transaction to change the owner permission of an account Each of the potential approvers of the proposed transaction (i.e. the active block producers) should first review the proposed transaction to make sure they are not approving anything that they do not agree to. +```sh +cleos multisig review blkproducera updatealice > wrap_update_alice_owner_trx_to_review.json +cat wrap_update_alice_owner_trx_to_review.json ``` -$ cleos multisig review blkproducera updatealice > wrap_update_alice_owner_trx_to_review.json -$ cat wrap_update_alice_owner_trx_to_review.json +```json { "proposal_name": "updatealice", "packed_transaction": "c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000", @@ -820,19 +900,29 @@ The approvers should go through the human-readable transaction output and make s Furthermore, even if this usability issue was fixed in nodeos/cleos, there will still be cases where there is no sensible human-readable version of an action data payload within a transaction. An example of this is the proposed transaction in sub-section 2.2.3 which used the `eosio::setcode` action to set the contract code of the `eosio.wrap` account. The best thing to do in such situations is for the reviewer to compare the proposed transaction to one generated by them through a process they trust. Since each block producer generated a transaction in sub-section 3.1.1 (stored in the file wrap_update_alice_owner_trx.json) which should be identical to the transaction proposed by the lead block producer, they can each simply check to see if the two transactions are identical: +```sh +cleos multisig propose_trx -j -s -d updatealice '[]' wrap_update_alice_owner_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_wrap_update_alice_owner_trx_serialized.hex +cat expected_wrap_update_alice_owner_trx_serialized.hex ``` -$ cleos multisig propose_trx -j -s -d updatealice '[]' wrap_update_alice_owner_trx.json blkproducera | grep '"data":' | sed 's/^[ \t]*"data":[ \t]*//;s/[",]//g' | cut -c 35- > expected_wrap_update_alice_owner_trx_serialized.hex -$ cat expected_wrap_update_alice_owner_trx_serialized.hex +```console c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 -$ cat wrap_update_alice_owner_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_wrap_update_alice_owner_trx_serialized.hex -$ cat proposed_wrap_update_alice_owner_trx_serialized.hex +``` +```sh +cat wrap_update_alice_owner_trx_to_review.json | grep '"packed_transaction":' | sed 's/^[ \t]*"packed_transaction":[ \t]*//;s/[",]//g' > proposed_wrap_update_alice_owner_trx_serialized.hex +cat proposed_wrap_update_alice_owner_trx_serialized.hex +``` +```console c0593f5b000000000000000000000100004d1a03ea305500000000008054570260ae423ad15b613c00000000a8ed323200004d1a03ea305500000000a8ed32326b60ae423ad15b613c0000000000000000000000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c340000000080ab26a700000000000000000100000000010000000000ea305500000000a8ed32320100000000 -$ diff expected_wrap_update_alice_owner_trx_serialized.hex proposed_wrap_update_alice_owner_trx_serialized.hex +``` +```sh +diff expected_wrap_update_alice_owner_trx_serialized.hex proposed_wrap_update_alice_owner_trx_serialized.hex ``` When an approver (e.g. `blkproducerb`) is satisfied with the proposed transaction, they can simply approve it: +```sh +cleos multisig approve blkproducera updatealice '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb ``` -$ cleos multisig approve blkproducera updatealice '{"actor": "blkproducerb", "permission": "active"}' -p blkproducerb +```console executed transaction: 2bddc7747e0660ba26babf95035225895b134bfb2ede32ba0a2bb6091c7dab56 128 bytes 543 us # eosio.msig <= eosio.msig::approve {"proposer":"blkproducera","proposal_name":"updatealice","level":{"actor":"blkproducerb","permission... warning: transaction executed locally, but may not be confirmed by the network yet @@ -842,16 +932,20 @@ warning: transaction executed locally, but may not be confirmed by the network y When the necessary approvals are collected (in this example, with 21 block producers, at least 15 of their approvals were required), anyone can push the `eosio.msig::exec` action which executes the approved transaction. It makes a lot of sense for the lead block producer who proposed the transaction to also execute it (this will incur another temporary RAM cost for the deferred transaction that is generated by the eosio.msig contract). +```sh +cleos multisig exec blkproducera updatealice blkproducera ``` -$ cleos multisig exec blkproducera updatealice blkproducera +```console executed transaction: 7127a66ae307fbef6415bf60c3e91a88b79bcb46030da983c683deb2a1a8e0d0 160 bytes 820 us # eosio.msig <= eosio.msig::exec {"proposer":"blkproducera","proposal_name":"updatealice","executer":"blkproducera"} warning: transaction executed locally, but may not be confirmed by the network yet ``` Anyone can now verify that the owner authority of `alice` was successfully changed: +```sh +cleos get account alice ``` -$ cleos get account alice +```console permissions: owner 1: 1 eosio@active, active 1: 1 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV From 42fd226b6feda8a8884742e6542b4d56de66bbca Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 6 Nov 2020 23:01:16 +0200 Subject: [PATCH 68/78] updates on cpu, net and ram documentation --- docs/01_key-concepts/01_system.md | 10 +++---- docs/01_key-concepts/02_ram.md | 17 +++++++---- docs/01_key-concepts/03_cpu.md | 10 +++++-- docs/01_key-concepts/04_net.md | 10 +++++-- docs/01_key-concepts/05_stake.md | 47 +++++++++++++++++++++++++++++-- docs/01_key-concepts/06_vote.md | 6 ++-- 6 files changed, 78 insertions(+), 22 deletions(-) diff --git a/docs/01_key-concepts/01_system.md b/docs/01_key-concepts/01_system.md index b3f6f2df1..eb14bb6da 100644 --- a/docs/01_key-concepts/01_system.md +++ b/docs/01_key-concepts/01_system.md @@ -1,18 +1,18 @@ --- content_title: System contracts, system accounts, privileged accounts -link_text: System contracts and accounts, privileged accounts +link_text: System contracts, system accounts, privileged accounts --- -At the genesis of an EOSIO based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](../#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `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` system account. +At the genesis of an EOSIO-based blockchain, there is only one account present, `eosio` account, which is the main `system account`. There are other `system account`s, created by `eosio` account, which control specific actions of the `system contract`s [mentioned in previous section](../#system-contracts-defined-in-eosio.contracts). __Note__ the terms `system contract` and `system account`. `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` system account. As you just learned the relation between a `system account` and a `system contract`, it is also important to remember that not all system accounts contain a system contract, but each system account has important roles in the blockchain functionality, as follows: |Account|Privileged|Has contract|Description| |---|---|---|---| -|eosio|Yes|It contains the `eosio.system` contract|The main system account on an EOSIO based blockchain.| +|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.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.| @@ -21,4 +21,4 @@ As you just learned the relation between a `system account` and a `system contra |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.| \ No newline at end of file +|eosio.rex|No|No|The account that keeps track of fees and balances resulted from REX related actions execution.| diff --git a/docs/01_key-concepts/02_ram.md b/docs/01_key-concepts/02_ram.md index afa832f81..a9d96fcd1 100644 --- a/docs/01_key-concepts/02_ram.md +++ b/docs/01_key-concepts/02_ram.md @@ -1,6 +1,6 @@ --- -content_title: RAM as resource -link_text: RAM as resource +content_title: RAM as system resource +link_text: RAM as system resource --- ## What is RAM @@ -23,10 +23,17 @@ The EOSIO-based blockchains are known for their high performance, which is achie ## RAM Importance -RAM is a very important resource because of the following reasons +RAM is a very important system 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 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. +- It is a limited resource, each EOSIO-based blockchain can have different policies 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 1KB per block, thus increasing constantly the supply of RAM for its price to not grow too high due to the increased demand from blockchain applications. - RAM is used in executing many actions sent to the blockchain; creating a new account action, 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). \ No newline at end of file +- The smart contract can not store any additional information if it consumes all its allocated RAM. To continue to save data in the blockchain database, one, or both of the following conditions must be met: + + - A portion of the occupied RAM is freed by the smart contract. + - More RAM is allocated to the smart contract account through the RAM buying process. + +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). + +The RAM system resource must be purchased using the system token. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-buy-ram) to learn how to buy RAM via the command line interface. diff --git a/docs/01_key-concepts/03_cpu.md b/docs/01_key-concepts/03_cpu.md index 43813698e..6f60577fe 100644 --- a/docs/01_key-concepts/03_cpu.md +++ b/docs/01_key-concepts/03_cpu.md @@ -1,6 +1,10 @@ --- -content_title: CPU as resource -link_text: CPU as resource +content_title: CPU as system resource +link_text: CPU as system resource --- -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. \ No newline at end of file +The system resource CPU provides processing power to blockchain accounts. The amount of CPU an account has is measured in microseconds and it is referred to as `cpu bandwidth` on the `cleos get account` command output. The `cpu bandwidth` represents the amount of processing time an account has at its disposal when actions sent to its contract are executed by the blockchain. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient CPU must be staked in order for transactions to complete. + +For more details about EOSIO staking refer to the following: +* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). +* [Staking on EOSIO-based blockchains](05_stake.md) \ No newline at end of file diff --git a/docs/01_key-concepts/04_net.md b/docs/01_key-concepts/04_net.md index a9b5aea14..f4f5b1460 100644 --- a/docs/01_key-concepts/04_net.md +++ b/docs/01_key-concepts/04_net.md @@ -1,6 +1,10 @@ --- -content_title: NET as resource -link_text: NET as resource +content_title: NET as system resource +link_text: NET as system resource --- -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. \ No newline at end of file +NET, as CPU and RAM, is a very important system resource in EOSIO-based blockchains. NET is measured by the byte size of the transactions saved in the blockchain database and it is referred to as `net bandwidth` on the cleos get account command result. When a transaction is executed by the blockchain it consumes CPU and NET, therefore sufficient NET must be staked in order for transactions to complete. + +For more details about EOSIO staking refer to the following: +* [Staking Mechanism](https://developers.eos.io/welcome/latest/overview/technical_features#staking-mechanism). +* [Staking on EOSIO-based blockchains](05_stake.md) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index c0fb29b28..bda754485 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -1,6 +1,47 @@ --- -content_title: Staking on EOSIO based blockchains -link_text: Staking on EOSIO based blockchains +content_title: Staking on EOSIO-based blockchains +link_text: Staking on EOSIO-based blockchains --- -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. \ No newline at end of file +## System Resources + +EOSIO-based blockchains work with three system resources: + +* [RAM](02_ram.md) +* [CPU](03_cpu.md) +* [NET](04_net.md) + +## How To Allocate System Resources + +EOSIO-based blockchain accounts need sufficient system resources, RAM, CPU and NET, to interact with the smart contracts deployed on the blockchain. + +### Stake NET and CPU + +The CPU and NET system resources are allocated by the account owner via the staking mechanism. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-stake-resource) on how to do it via the command line interface. + +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 will 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. + +When you stake tokens for CPU and NET, you gain access to system resources proportional to the total amount of tokens staked by all other users for the same system resource at the same time. This means you can execute transactions at no cost but in the limits of the staked tokens. The staked tokens guarantee the proportional amount of resources regardless of any variations in the free market. + +If an account consumes all its allocated CPU and NET resources, it has two options: + +* It can wait for the blockchain to replenish the consumed resources. You can read more details below about the [system resources replenish algorithm].(05_stake.md#System-Resources-Replenish-Algorithm). +* It can allocate more resources through the staking mechanism. + +When an account uses the allocated resources, the amount that can be used in one transaction is limited by predefine [maximum CPU](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-max_transaction_cpu_usage), [minimum CPU](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-min_transaction_cpu_usage), and [maximum NET](https://developers.eos.io/manuals/eosio.cdt/latest/structeosio_1_1blockchain__parameters#variable-max_transaction_net_usage) limits. Transactions executed by the blockchain contain one or more actions, and each transaction must consume an amount of CPU and NET which is in the limits defined by the aforementioned blockchain settings. + +#### System Resources Replenish Algorithm + +EOSIO-based blockchains replenish automatically the consumed CPU and NET system resources. Before a transaction is executed, by the blockchain, it first calculates how many resources the account executing the transaction can consume. The calculation uses an exponential moving average with linear extrapolation when data is missing, and it multiplies the currently accumulated average by `(number of blocks in the window - number of blocks since last update) / (number of blocks in the window)`. The window is set as 24 hours window. + +This formula has the following outcomes: + +* If an account waited `number of blocks in the window` without executing any transaction it resets to zero usage. + +* If an account issues a transaction with every block it would always be `(number of blocks in the window - 1) / (number of blocks in the window)`, a very small value, very close to zero. Mathematically it _never_ reaches zero but the EOSIO implementation truncates off the tiny numbers to zero. + +* The accounts that execute transactions more often than the ones that execute less transactions, replenish their resources slower than the later. In other words, the more transactions an account executes the slower the replenish of resources. + +### Buy RAM + +The RAM resource must be bought using the system token. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. diff --git a/docs/01_key-concepts/06_vote.md b/docs/01_key-concepts/06_vote.md index 5daaac725..4aa8ba6b1 100644 --- a/docs/01_key-concepts/06_vote.md +++ b/docs/01_key-concepts/06_vote.md @@ -1,6 +1,6 @@ --- -content_title: Voting on EOSIO based blockchains -link_text: Voting on EOSIO based blockchains +content_title: Voting on EOSIO-based blockchains +link_text: Voting on EOSIO-based blockchains --- -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. \ No newline at end of file +In a EOSIO-based network the blockchain is kept alive by nodes which are interconnected between each other, 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. 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. The 21 producers is the default value however it can be configured to be higher or smaller to meet each business case requirements. From a726337233e00b335c00bf380350e76a583ed77a Mon Sep 17 00:00:00 2001 From: iamveritas Date: Fri, 6 Nov 2020 23:31:44 +0200 Subject: [PATCH 69/78] Add specific info for 1.9.x --- docs/01_key-concepts/05_stake.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/01_key-concepts/05_stake.md b/docs/01_key-concepts/05_stake.md index bda754485..d8904d9d3 100644 --- a/docs/01_key-concepts/05_stake.md +++ b/docs/01_key-concepts/05_stake.md @@ -42,6 +42,9 @@ This formula has the following outcomes: * The accounts that execute transactions more often than the ones that execute less transactions, replenish their resources slower than the later. In other words, the more transactions an account executes the slower the replenish of resources. +[[info]] +| The blockchain calculates and updates the remaining resources, for the accounts which execute transactions, with each block, before each transaction is executed. As time passes, as explained above, the consumed system resources are gradually replenished, and the available system resources increase, or decrease, depending on how many transactions an account executes. After waiting for some time, if you check the available resources balance and expect to see it increased, because your account did not executed any transactions, you will not see it updated. That is because it gets updated only before a transaction is executed. Therefore in order to see the available resources you have to execute a transaction. This is counter intuitive and the next versions will improve this aspect. + ### Buy RAM The RAM resource must be bought using the system token. Refer to the [cleos manual](https://developers.eos.io/manuals/eos/v2.0/cleos/how-to-guides/how-to-buy-ram) to learn how to do it via the command line interface. When an account consumes all its allocated RAM can not store any additional information on the blockchain database until it frees some of the occupied RAM or more RAM is allocated to the account through the RAM buying process. From 7692a8af47aec48c7d3bb2944af1bcb0153c4034 Mon Sep 17 00:00:00 2001 From: deck Date: Mon, 30 Nov 2020 12:12:49 -0500 Subject: [PATCH 70/78] rename rentbw to powerup --- contracts/eosio.system/CMakeLists.txt | 11 +- .../include/eosio.system/eosio.system.hpp | 85 ++--- .../include/eosio.system/powerup.results.hpp | 33 ++ .../src/{rentbw.cpp => powerup.cpp} | 87 ++--- .../eosio.system/src/powerup.results.cpp | 5 + ...ntbw_tests.cpp => eosio.powerup_tests.cpp} | 304 +++++++++--------- 6 files changed, 289 insertions(+), 236 deletions(-) create mode 100644 contracts/eosio.system/include/eosio.system/powerup.results.hpp rename contracts/eosio.system/src/{rentbw.cpp => powerup.cpp} (81%) create mode 100644 contracts/eosio.system/src/powerup.results.cpp rename tests/{eosio.rentbw_tests.cpp => eosio.powerup_tests.cpp} (77%) diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt index 585525430..6b47d1563 100644 --- a/contracts/eosio.system/CMakeLists.txt +++ b/contracts/eosio.system/CMakeLists.txt @@ -5,7 +5,7 @@ add_contract(eosio.system eosio.system ${CMAKE_CURRENT_SOURCE_DIR}/src/name_bidding.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/native.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/producer_pay.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/rentbw.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/powerup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/voting.cpp ) @@ -20,15 +20,24 @@ set_target_properties(eosio.system RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") add_contract(rex.results rex.results ${CMAKE_CURRENT_SOURCE_DIR}/src/rex.results.cpp) +add_contract(powup.results powup.results ${CMAKE_CURRENT_SOURCE_DIR}/src/powerup.results.cpp) target_include_directories(rex.results PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(powup.results + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include) + set_target_properties(rex.results PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.rex") +set_target_properties(powup.results + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/.powerup") + 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/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2479205a2..a70726f18 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -40,7 +40,7 @@ namespace eosiosystem { using eosio::time_point_sec; using eosio::unsigned_int; - inline constexpr int64_t rentbw_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 + inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 template static inline auto has_field( F flags, E field ) @@ -525,7 +525,7 @@ namespace eosiosystem { asset stake_change; }; - struct rentbw_config_resource { + struct powerup_config_resource { std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. // Do not specify to preserve the existing setting or use the default; // this avoids sudden price jumps. For new chains which don't need @@ -534,7 +534,7 @@ namespace eosiosystem { std::optional target_weight_ratio; // Linearly shrink weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. // Do not specify to preserve the existing setting or use the default. std::optional assumed_stake_weight; // Assumed stake weight for ratio calculations. Use the sum of total - // staked and total rented by REX at the time the rentbw market + // staked and total rented by REX at the time the power market // is first activated. Do not specify to preserve the existing // setting (no default exists); this avoids sudden price jumps. // For new chains which don't need to phase out staking and REX, @@ -558,22 +558,22 @@ namespace eosiosystem { // token supply. Do not specify to preserve the existing // setting (no default exists). - EOSLIB_SERIALIZE( rentbw_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) + EOSLIB_SERIALIZE( powerup_config_resource, (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight) (target_timestamp)(exponent)(decay_secs)(min_price)(max_price) ) }; - struct rentbw_config { - rentbw_config_resource net; // NET market configuration - rentbw_config_resource cpu; // CPU market configuration - std::optional rent_days; // `rentbw` `days` argument must match this. Do not specify to preserve the + struct powerup_config { + powerup_config_resource net; // NET market configuration + powerup_config_resource cpu; // CPU market configuration + std::optional powerup_days; // `power` `days` argument must match this. Do not specify to preserve the // existing setting or use the default. - std::optional min_rent_fee; // Rental fees below this amount are rejected. Do not specify to preserve the + std::optional min_powerup_fee; // Rental fees below this amount are rejected. Do not specify to preserve the // existing setting (no default exists). - EOSLIB_SERIALIZE( rentbw_config, (net)(cpu)(rent_days)(min_rent_fee) ) + EOSLIB_SERIALIZE( powerup_config, (net)(cpu)(powerup_days)(min_powerup_fee) ) }; - struct rentbw_state_resource { + struct powerup_state_resource { static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a // tiny amount of resources increases linearly // with utilization. @@ -591,8 +591,8 @@ namespace eosiosystem { // assumed_stake_weight / (assumed_stake_weight + weight). // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. - int64_t initial_weight_ratio = rentbw_frac; // Initial weight_ratio used for linear shrinkage. - int64_t target_weight_ratio = rentbw_frac / 100; // Linearly shrink the weight_ratio to this amount. + int64_t initial_weight_ratio = powerup_frac; // Initial weight_ratio used for linear shrinkage. + int64_t target_weight_ratio = powerup_frac / 100; // Linearly shrink the weight_ratio to this amount. time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this // time hits, weight_ratio will be target_weight_ratio. @@ -610,21 +610,21 @@ namespace eosiosystem { time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated }; - struct [[eosio::table("rent.state"),eosio::contract("eosio.system")]] rentbw_state { - static constexpr uint32_t default_rent_days = 30; // 30 day resource rentals + struct [[eosio::table("powup.state"),eosio::contract("eosio.system")]] powerup_state { + static constexpr uint32_t default_powerup_days = 30; // 30 day resource powerups - uint8_t version = 0; - rentbw_state_resource net = {}; // NET market state - rentbw_state_resource cpu = {}; // CPU market state - uint32_t rent_days = default_rent_days; // `rentbw` `days` argument must match this. - asset min_rent_fee = {}; // Rental fees below this amount are rejected + uint8_t version = 0; + powerup_state_resource net = {}; // NET market state + powerup_state_resource cpu = {}; // CPU market state + uint32_t powerup_days = default_powerup_days; // `powerup` `days` argument must match this. + asset min_powerup_fee = {}; // fees below this amount are rejected uint64_t primary_key()const { return 0; } }; - typedef eosio::singleton<"rent.state"_n, rentbw_state> rentbw_state_singleton; + typedef eosio::singleton<"powup.state"_n, powerup_state> powerup_state_singleton; - struct [[eosio::table("rentbw.order"),eosio::contract("eosio.system")]] rentbw_order { + struct [[eosio::table("powup.order"),eosio::contract("eosio.system")]] powerup_order { uint8_t version = 0; uint64_t id; name owner; @@ -637,13 +637,16 @@ namespace eosiosystem { uint64_t by_expires()const { return expires.utc_seconds; } }; - typedef eosio::multi_index< "rentbw.order"_n, rentbw_order, - indexed_by<"byowner"_n, const_mem_fun>, - indexed_by<"byexpires"_n, const_mem_fun> - > rentbw_order_table; + typedef eosio::multi_index< "powup.order"_n, powerup_order, + indexed_by<"byowner"_n, const_mem_fun>, + indexed_by<"byexpires"_n, const_mem_fun> + > powerup_order_table; /** - * eosio.system contract defines the structures and actions needed for blockchain's core functionality. + * The `eosio.system` smart contract is provided by `block.one` as a sample system contract, and it defines the structures and actions needed for blockchain's core functionality. + * + * Just like in the `eosio.bios` sample contract implementation, there are a few actions which are not implemented at the contract level (`newaccount`, `updateauth`, `deleteauth`, `linkauth`, `unlinkauth`, `canceldelay`, `onerror`, `setabi`, `setcode`), they are just declared in the contract so they will show in the contract's ABI and users will be able to push those actions to the chain via the account holding the `eosio.system` contract, but the implementation is at the EOSIO core level. They are referred to as EOSIO native actions. + * * - Users can stake tokens for CPU and Network bandwidth, and then vote for producers or * delegate their vote to a proxy. * - Producers register in order to be voted for, and can claim per-block and per-vote rewards. @@ -651,7 +654,7 @@ 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 resource market separate from REX: `rentbw`. + * - A resource market separate from REX: `power`. */ class [[eosio::contract("eosio.system")]] system_contract : public native { @@ -1296,23 +1299,23 @@ namespace eosiosystem { void setinflation( int64_t annual_rate, int64_t inflation_pay_factor, int64_t votepay_factor ); /** - * Configure the `rentbw` market. The market becomes available the first time this + * Configure the `power` market. The market becomes available the first time this * action is invoked. */ [[eosio::action]] - void configrentbw( rentbw_config& args ); + void cfgpowerup( powerup_config& args ); /** - * Process rentbw queue and update state. Action does not execute anything related to a specific user. + * Process power queue and update state. Action does not execute anything related to a specific user. * * @param user - any account can execute this action * @param max - number of queue items to process */ [[eosio::action]] - void rentbwexec( const name& user, uint16_t max ); + void powerupexec( const name& user, uint16_t max ); /** - * Rent NET and CPU + * Rent NET and CPU by percentage * * @param payer - the resource buyer * @param receiver - the resource receiver @@ -1323,7 +1326,7 @@ namespace eosiosystem { * `payer`'s token balance. */ [[eosio::action]] - void rentbw( const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment ); + void powerup( const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment ); using init_action = eosio::action_wrapper<"init"_n, &system_contract::init>; using setacctram_action = eosio::action_wrapper<"setacctram"_n, &system_contract::setacctram>; @@ -1371,9 +1374,9 @@ namespace eosiosystem { using setalimits_action = eosio::action_wrapper<"setalimits"_n, &system_contract::setalimits>; using setparams_action = eosio::action_wrapper<"setparams"_n, &system_contract::setparams>; using setinflation_action = eosio::action_wrapper<"setinflation"_n, &system_contract::setinflation>; - using configrentbw_action = eosio::action_wrapper<"configrentbw"_n, &system_contract::configrentbw>; - using rentbwexec_action = eosio::action_wrapper<"rentbwexec"_n, &system_contract::rentbwexec>; - using rentbw_action = eosio::action_wrapper<"rentbw"_n, &system_contract::rentbw>; + using cfgpowerup_action = eosio::action_wrapper<"cfgpowerup"_n, &system_contract::cfgpowerup>; + using powerupexec_action = eosio::action_wrapper<"powerupexec"_n, &system_contract::powerupexec>; + using powerup_action = eosio::action_wrapper<"powerup"_n, &system_contract::powerup>; private: // Implementation details: @@ -1475,11 +1478,11 @@ namespace eosiosystem { registration<&system_contract::update_rex_stake> vote_stake_updater{ this }; - // defined in rentbw.cpp + // defined in power.cpp void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); - void process_rentbw_queue( - time_point_sec now, symbol core_symbol, rentbw_state& state, - rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, + void process_queue( + time_point_sec now, symbol core_symbol, powerup_state& state, + powerup_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available); }; diff --git a/contracts/eosio.system/include/eosio.system/powerup.results.hpp b/contracts/eosio.system/include/eosio.system/powerup.results.hpp new file mode 100644 index 000000000..52d86cd12 --- /dev/null +++ b/contracts/eosio.system/include/eosio.system/powerup.results.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +using eosio::action_wrapper; +using eosio::asset; +using eosio::name; + +/** + * The action `powerresult` of `power.results` is a no-op. + * It is added as an inline convenience action to `power` rental. + * This 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("powup.results")]] powup_results : eosio::contract { + public: + + using eosio::contract::contract; + + /** + * powupresult action. + * + * @param fee - rental fee amount + * @param powup_net - amount of powup NET tokens + * @param powup_cpu - amount of powup CPU tokens + */ + [[eosio::action]] + void powupresult( const asset& fee, const asset& powup_net, const asset& powup_cpu ); + + using powupresult_action = action_wrapper<"powupresult"_n, &powup_results::powupresult>; +}; diff --git a/contracts/eosio.system/src/rentbw.cpp b/contracts/eosio.system/src/powerup.cpp similarity index 81% rename from contracts/eosio.system/src/rentbw.cpp rename to contracts/eosio.system/src/powerup.cpp index 195f53d37..ebab2615b 100644 --- a/contracts/eosio.system/src/rentbw.cpp +++ b/contracts/eosio.system/src/powerup.cpp @@ -1,11 +1,12 @@ #include #include +#include #include #include namespace eosiosystem { -void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available); +void update_weight(time_point_sec now, powerup_state_resource& res, int64_t& delta_available); /** * @pre now >= res.utilization_timestamp @@ -13,7 +14,7 @@ void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delt * @post if res.utilization < old res.adjusted_utilization, then new res.adjusted_utilization <= old res.adjusted_utilization * @post if res.utilization >= old res.adjusted_utilization, then new res.adjusted_utilization == res.utilization */ -void update_utilization(time_point_sec now, rentbw_state_resource& res); +void update_utilization(time_point_sec now, powerup_state_resource& res); void system_contract::adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed) { @@ -66,8 +67,8 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym } } // system_contract::adjust_resources -void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbol, rentbw_state& state, - rentbw_order_table& orders, uint32_t max_items, int64_t& net_delta_available, +void system_contract::process_queue(time_point_sec now, symbol core_symbol, powerup_state& state, + powerup_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available) { update_utilization(now, state.net); update_utilization(now, state.cpu); @@ -87,7 +88,7 @@ void system_contract::process_rentbw_queue(time_point_sec now, symbol core_symbo update_weight(now, state.cpu, cpu_delta_available); } -void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delta_available) { +void update_weight(time_point_sec now, powerup_state_resource& res, int64_t& delta_available) { if (now >= res.target_timestamp) { res.weight_ratio = res.target_weight_ratio; } else { @@ -96,12 +97,12 @@ void update_weight(time_point_sec now, rentbw_state_resource& res, int64_t& delt (now.utc_seconds - res.initial_timestamp.utc_seconds) / (res.target_timestamp.utc_seconds - res.initial_timestamp.utc_seconds); } - int64_t new_weight = res.assumed_stake_weight * int128_t(rentbw_frac) / res.weight_ratio - res.assumed_stake_weight; + int64_t new_weight = res.assumed_stake_weight * int128_t(powerup_frac) / res.weight_ratio - res.assumed_stake_weight; delta_available += new_weight - res.weight; res.weight = new_weight; } -void update_utilization(time_point_sec now, rentbw_state_resource& res) { +void update_utilization(time_point_sec now, powerup_state_resource& res) { if (now <= res.utilization_timestamp) return; if (res.utilization >= res.adjusted_utilization) { @@ -115,11 +116,11 @@ void update_utilization(time_point_sec now, rentbw_state_resource& res) { res.utilization_timestamp = now; } -void system_contract::configrentbw(rentbw_config& args) { +void system_contract::cfgpowerup(powerup_config& args) { require_auth(get_self()); time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); - rentbw_state_singleton state_sing{ get_self(), 0 }; + powerup_state_singleton state_sing{ get_self(), 0 }; auto state = state_sing.get_or_default(); eosio::check(eosio::is_account(reserv_account), "eosio.reserv account must first be created"); @@ -191,12 +192,12 @@ void system_contract::configrentbw(rentbw_config& args) { } eosio::check(*args.current_weight_ratio > 0, "current_weight_ratio is too small"); - eosio::check(*args.current_weight_ratio <= rentbw_frac, "current_weight_ratio is too large"); + eosio::check(*args.current_weight_ratio <= powerup_frac, "current_weight_ratio is too large"); eosio::check(*args.target_weight_ratio > 0, "target_weight_ratio is too small"); eosio::check(*args.target_weight_ratio <= *args.current_weight_ratio, "weight can't grow over time"); eosio::check(*args.assumed_stake_weight >= 1, "assumed_stake_weight must be at least 1; a much larger value is recommended"); - eosio::check(*args.assumed_stake_weight * int128_t(rentbw_frac) / *args.target_weight_ratio <= + eosio::check(*args.assumed_stake_weight * int128_t(powerup_frac) / *args.target_weight_ratio <= std::numeric_limits::max(), "assumed_stake_weight/target_weight_ratio is too large"); eosio::check(*args.exponent >= 1.0, "exponent must be >= 1"); @@ -221,21 +222,21 @@ void system_contract::configrentbw(rentbw_config& args) { state.max_price = *args.max_price; }; - if (!args.rent_days) { - *args.rent_days = state.rent_days; + if (!args.powerup_days) { + *args.powerup_days = state.powerup_days; } - if (!args.min_rent_fee) { - eosio::check(!is_default_asset(state.min_rent_fee), "min_rent_fee does not have a default value"); - *args.min_rent_fee = state.min_rent_fee; + if (!args.min_powerup_fee) { + eosio::check(!is_default_asset(state.min_powerup_fee), "min_powerup_fee does not have a default value"); + *args.min_powerup_fee = state.min_powerup_fee; } - eosio::check(*args.rent_days > 0, "rent_days must be > 0"); - eosio::check(args.min_rent_fee->symbol == core_symbol, "min_rent_fee doesn't match core symbol"); - eosio::check(args.min_rent_fee->amount > 0, "min_rent_fee must be positive"); + eosio::check(*args.powerup_days > 0, "powerup_days must be > 0"); + eosio::check(args.min_powerup_fee->symbol == core_symbol, "min_powerup_fee doesn't match core symbol"); + eosio::check(args.min_powerup_fee->amount > 0, "min_powerup_fee must be positive"); - state.rent_days = *args.rent_days; - state.min_rent_fee = *args.min_rent_fee; + state.powerup_days = *args.powerup_days; + state.min_powerup_fee = *args.min_powerup_fee; update(state.net, args.net); update(state.cpu, args.cpu); @@ -249,7 +250,7 @@ void system_contract::configrentbw(rentbw_config& args) { adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); -} // system_contract::configrentbw +} // system_contract::configpower /** * @pre 0 <= state.min_price.amount <= state.max_price.amount @@ -258,7 +259,7 @@ void system_contract::configrentbw(rentbw_config& args) { * @pre 0 <= state.utilization <= state.adjusted_utilization <= state.weight * @pre 0 <= utilization_increase <= (state.weight - state.utilization) */ -int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_increase) { +int64_t calc_powerup_fee(const powerup_state_resource& state, int64_t utilization_increase) { if( utilization_increase <= 0 ) return 0; // Let p(u) = price as a function of the utilization fraction u which is defined for u in [0.0, 1.0]. @@ -278,8 +279,6 @@ int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_ coefficient * std::pow(end_u, state.exponent) - coefficient * std::pow(start_u, state.exponent); }; - // Returns p(double(utilization)/state.weight). - // @pre 0 <= utilization <= state.weight auto price_function = [&state](int64_t utilization) -> double { double price = state.min_price.amount; // state.exponent >= 1.0, therefore the exponent passed into std::pow is >= 0.0. @@ -313,51 +312,51 @@ int64_t calc_rentbw_fee(const rentbw_state_resource& state, int64_t utilization_ return std::ceil(fee); } -void system_contract::rentbwexec(const name& user, uint16_t max) { +void system_contract::powerupexec(const name& user, uint16_t max) { require_auth(user); - rentbw_state_singleton state_sing{ get_self(), 0 }; - rentbw_order_table orders{ get_self(), 0 }; - eosio::check(state_sing.exists(), "rentbw hasn't been initialized"); + powerup_state_singleton state_sing{ get_self(), 0 }; + powerup_order_table orders{ get_self(), 0 }; + eosio::check(state_sing.exists(), "powerup hasn't been initialized"); auto state = state_sing.get(); time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - process_rentbw_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); + process_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); } -void system_contract::rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, +void system_contract::powerup(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment) { require_auth(payer); - rentbw_state_singleton state_sing{ get_self(), 0 }; - rentbw_order_table orders{ get_self(), 0 }; - eosio::check(state_sing.exists(), "rentbw hasn't been initialized"); + powerup_state_singleton state_sing{ get_self(), 0 }; + powerup_order_table orders{ get_self(), 0 }; + eosio::check(state_sing.exists(), "powerup hasn't been initialized"); auto state = state_sing.get(); time_point_sec now = eosio::current_time_point(); auto core_symbol = get_core_symbol(); eosio::check(max_payment.symbol == core_symbol, "max_payment doesn't match core symbol"); - eosio::check(days == state.rent_days, "days doesn't match configuration"); + eosio::check(days == state.powerup_days, "days doesn't match configuration"); eosio::check(net_frac >= 0, "net_frac can't be negative"); eosio::check(cpu_frac >= 0, "cpu_frac can't be negative"); - eosio::check(net_frac <= rentbw_frac, "net can't be more than 100%"); - eosio::check(cpu_frac <= rentbw_frac, "cpu can't be more than 100%"); + eosio::check(net_frac <= powerup_frac, "net can't be more than 100%"); + eosio::check(cpu_frac <= powerup_frac, "cpu can't be more than 100%"); int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - process_rentbw_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); + process_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); eosio::asset fee{ 0, core_symbol }; - auto process = [&](int64_t frac, int64_t& amount, rentbw_state_resource& state) { + auto process = [&](int64_t frac, int64_t& amount, powerup_state_resource& state) { if (!frac) return; - amount = int128_t(frac) * state.weight / rentbw_frac; + amount = int128_t(frac) * state.weight / powerup_frac; eosio::check(state.weight, "market doesn't have resources available"); eosio::check(state.utilization + amount <= state.weight, "market doesn't have enough resources available"); - int64_t f = calc_rentbw_fee(state, amount); + int64_t f = calc_powerup_fee(state, amount); eosio::check(f > 0, "calculated fee is below minimum; try renting more"); fee.amount += f; state.utilization += amount; @@ -372,7 +371,7 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d error_msg += fee.to_string(); eosio::check(false, error_msg); } - eosio::check(fee >= state.min_rent_fee, "calculated fee is below minimum; try renting more"); + eosio::check(fee >= state.min_powerup_fee, "calculated fee is below minimum; try renting more"); orders.emplace(payer, [&](auto& order) { order.id = orders.available_primary_key(); @@ -388,6 +387,10 @@ void system_contract::rentbw(const name& payer, const name& receiver, uint32_t d adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); channel_to_rex(payer, fee, true); state_sing.set(state, get_self()); + + // inline noop action + powup_results::powupresult_action powupresult_act{ reserv_account, std::vector{ } }; + powupresult_act.send( fee, asset{ net_amount, core_symbol }, asset{ cpu_amount, core_symbol } ); } } // namespace eosiosystem diff --git a/contracts/eosio.system/src/powerup.results.cpp b/contracts/eosio.system/src/powerup.results.cpp new file mode 100644 index 000000000..7b9c80269 --- /dev/null +++ b/contracts/eosio.system/src/powerup.results.cpp @@ -0,0 +1,5 @@ +#include + +void powup_results::powupresult( const asset& fee, const asset& powup_net, const asset& powup_cpu ) { } + +extern "C" void apply( uint64_t, uint64_t, uint64_t ) { } diff --git a/tests/eosio.rentbw_tests.cpp b/tests/eosio.powerup_tests.cpp similarity index 77% rename from tests/eosio.rentbw_tests.cpp rename to tests/eosio.powerup_tests.cpp index 115bfa838..fa12fc073 100644 --- a/tests/eosio.rentbw_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -12,10 +12,10 @@ #include "eosio.system_tester.hpp" -inline constexpr int64_t rentbw_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 +inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 inline constexpr int64_t stake_weight = 100'000'000'0000ll; // 10^12 -struct rentbw_config_resource { +struct powerup_config_resource { fc::optional current_weight_ratio = {}; fc::optional target_weight_ratio = {}; fc::optional assumed_stake_weight = {}; @@ -25,19 +25,19 @@ struct rentbw_config_resource { fc::optional min_price = {}; fc::optional max_price = {}; }; -FC_REFLECT(rentbw_config_resource, // +FC_REFLECT(powerup_config_resource, // (current_weight_ratio)(target_weight_ratio)(assumed_stake_weight)(target_timestamp) // (exponent)(decay_secs)(min_price)(max_price)) -struct rentbw_config { - rentbw_config_resource net = {}; - rentbw_config_resource cpu = {}; - fc::optional rent_days = {}; - fc::optional min_rent_fee = {}; +struct powerup_config { + powerup_config_resource net = {}; + powerup_config_resource cpu = {}; + fc::optional powerup_days = {}; + fc::optional min_powerup_fee = {}; }; -FC_REFLECT(rentbw_config, (net)(cpu)(rent_days)(min_rent_fee)) +FC_REFLECT(powerup_config, (net)(cpu)(powerup_days)(min_powerup_fee)) -struct rentbw_state_resource { +struct powerup_state_resource { uint8_t version; int64_t weight; int64_t weight_ratio; @@ -54,25 +54,25 @@ struct rentbw_state_resource { int64_t adjusted_utilization; time_point_sec utilization_timestamp; }; -FC_REFLECT(rentbw_state_resource, // +FC_REFLECT(powerup_state_resource, // (version)(weight)(weight_ratio)(assumed_stake_weight)(initial_weight_ratio)(target_weight_ratio) // (initial_timestamp)(target_timestamp)(exponent)(decay_secs)(min_price)(max_price)(utilization) // (adjusted_utilization)(utilization_timestamp)) -struct rentbw_state { +struct powerup_state { uint8_t version; - rentbw_state_resource net; - rentbw_state_resource cpu; - uint32_t rent_days; - asset min_rent_fee; + powerup_state_resource net; + powerup_state_resource cpu; + uint32_t powerup_days; + asset min_powerup_fee; }; -FC_REFLECT(rentbw_state, (version)(net)(cpu)(rent_days)(min_rent_fee)) +FC_REFLECT(powerup_state, (version)(net)(cpu)(powerup_days)(min_powerup_fee)) using namespace eosio_system; -struct rentbw_tester : eosio_system_tester { +struct powerup_tester : eosio_system_tester { - rentbw_tester() { create_accounts_with_resources({ N(eosio.reserv) }); } + powerup_tester() { create_accounts_with_resources({ N(eosio.reserv) }); } void start_rex() { create_account_with_resources(N(rexholder111), config::system_account_name, core_sym::from_string("1.0000"), @@ -92,11 +92,11 @@ struct rentbw_tester : eosio_system_tester { } template - rentbw_config make_config(F f) { - rentbw_config config; + powerup_config make_config(F f) { + powerup_config config; - config.net.current_weight_ratio = rentbw_frac; - config.net.target_weight_ratio = rentbw_frac / 100; + config.net.current_weight_ratio = powerup_frac; + config.net.target_weight_ratio = powerup_frac / 100; config.net.assumed_stake_weight = stake_weight; config.net.target_timestamp = control->head_block_time() + fc::days(100); config.net.exponent = 2; @@ -104,8 +104,8 @@ struct rentbw_tester : eosio_system_tester { config.net.min_price = asset::from_string("0.0000 TST"); config.net.max_price = asset::from_string("1000000.0000 TST"); - config.cpu.current_weight_ratio = rentbw_frac; - config.cpu.target_weight_ratio = rentbw_frac / 100; + config.cpu.current_weight_ratio = powerup_frac; + config.cpu.target_weight_ratio = powerup_frac / 100; config.cpu.assumed_stake_weight = stake_weight; config.cpu.target_timestamp = control->head_block_time() + fc::days(100); config.cpu.exponent = 2; @@ -113,25 +113,25 @@ struct rentbw_tester : eosio_system_tester { config.cpu.min_price = asset::from_string("0.0000 TST"); config.cpu.max_price = asset::from_string("1000000.0000 TST"); - config.rent_days = 30; - config.min_rent_fee = asset::from_string("1.0000 TST"); + config.powerup_days = 30; + config.min_powerup_fee = asset::from_string("1.0000 TST"); f(config); return config; } - rentbw_config make_config() { + powerup_config make_config() { return make_config([](auto&) {}); } template - rentbw_config make_default_config(F f) { - rentbw_config config; + powerup_config make_default_config(F f) { + powerup_config config; f(config); return config; } - action_result configbw(const rentbw_config& config) { + action_result configbw(const powerup_config& config) { // Verbose solution needed to work around bug in abi_serializer that fails if optional values aren't explicitly // specified with a null value. @@ -139,7 +139,7 @@ struct rentbw_tester : eosio_system_tester { return (!v ? fc::variant() : fc::variant(*v)); }; - auto resource_conf_vo = [&optional_to_variant](const rentbw_config_resource& c ) { + auto resource_conf_vo = [&optional_to_variant](const powerup_config_resource& c ) { return mvo("current_weight_ratio", optional_to_variant(c.current_weight_ratio)) ("target_weight_ratio", optional_to_variant(c.target_weight_ratio)) ("assumed_stake_weight", optional_to_variant(c.assumed_stake_weight)) @@ -153,31 +153,31 @@ struct rentbw_tester : eosio_system_tester { auto conf = mvo("net", resource_conf_vo(config.net)) ("cpu", resource_conf_vo(config.cpu)) - ("rent_days", optional_to_variant(config.rent_days)) - ("min_rent_fee", optional_to_variant(config.min_rent_fee)) + ("powerup_days", optional_to_variant(config.powerup_days)) + ("min_powerup_fee", optional_to_variant(config.min_powerup_fee)) ; //idump((fc::json::to_pretty_string(conf))); - return push_action(config::system_account_name, N(configrentbw), mvo()("args", std::move(conf))); + return push_action(config::system_account_name, N(cfgpowerup), mvo()("args", std::move(conf))); // If abi_serializer worked correctly, the following is all that would be needed: - //return push_action(config::system_account_name, N(configrentbw), mvo()("args", config)); + //return push_action(config::system_account_name, N(cfgpowerup), mvo()("args", config)); } - action_result rentbwexec(name user, uint16_t max) { - return push_action(user, N(rentbwexec), mvo()("user", user)("max", max)); + action_result powerupexec(name user, uint16_t max) { + return push_action(user, N(powerupexec), mvo()("user", user)("max", max)); } - action_result rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, + action_result powerup(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& max_payment) { - return push_action(payer, N(rentbw), + return push_action(payer, N(powerup), mvo()("payer", payer)("receiver", receiver)("days", days)("net_frac", net_frac)( "cpu_frac", cpu_frac)("max_payment", max_payment)); } - rentbw_state get_state() { - vector data = get_row_by_account(config::system_account_name, {}, N(rent.state), N(rent.state)); - return fc::raw::unpack(data); + powerup_state get_state() { + vector data = get_row_by_account(config::system_account_name, {}, N(powup.state), N(powup.state)); + return fc::raw::unpack(data); } struct account_info { @@ -194,13 +194,13 @@ struct rentbw_tester : eosio_system_tester { return info; }; - void check_rentbw(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, + void check_powerup(const name& payer, const name& receiver, uint32_t days, int64_t net_frac, int64_t cpu_frac, const asset& expected_fee, int64_t expected_net, int64_t expected_cpu) { auto before_payer = get_account_info(payer); auto before_receiver = get_account_info(receiver); auto before_reserve = get_account_info(N(eosio.reserv)); auto before_state = get_state(); - BOOST_REQUIRE_EQUAL("", rentbw(payer, receiver, days, net_frac, cpu_frac, expected_fee)); + BOOST_REQUIRE_EQUAL("", powerup(payer, receiver, days, net_frac, cpu_frac, expected_fee)); auto after_payer = get_account_info(payer); auto after_receiver = get_account_info(receiver); auto after_reserve = get_account_info(N(eosio.reserv)); @@ -209,7 +209,7 @@ struct rentbw_tester : eosio_system_tester { if (false) { ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); ilog("before_state.net.weight_ratio: ${x}", - ("x", before_state.net.weight_ratio / double(rentbw_frac))); + ("x", before_state.net.weight_ratio / double(powerup_frac))); ilog("before_state.net.assumed_stake_weight: ${x}", ("x", before_state.net.assumed_stake_weight)); ilog("before_state.net.weight: ${x}", ("x", before_state.net.weight)); @@ -252,35 +252,35 @@ bool near(A a, B b, D delta) { return false; } -BOOST_AUTO_TEST_SUITE(eosio_system_rentbw_tests) +BOOST_AUTO_TEST_SUITE(eosio_system_powerup_tests) -BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { +BOOST_FIXTURE_TEST_CASE(config_tests, powerup_tester) try { BOOST_REQUIRE_EQUAL("missing authority of eosio", - push_action(N(alice1111111), N(configrentbw), mvo()("args", make_config()))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("rentbw hasn't been initialized"), rentbwexec(N(alice1111111), 10)); + push_action(N(alice1111111), N(cfgpowerup), mvo()("args", make_config()))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("powerup hasn't been initialized"), powerupexec(N(alice1111111), 10)); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("rent_days must be > 0"), - configbw(make_config([&](auto& c) { c.rent_days = 0; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee doesn't match core symbol"), configbw(make_config([&](auto& c) { - c.min_rent_fee = asset::from_string("1000000.000 TST"); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("powerup_days must be > 0"), + configbw(make_config([&](auto& c) { c.powerup_days = 0; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_powerup_fee doesn't match core symbol"), configbw(make_config([&](auto& c) { + c.min_powerup_fee = asset::from_string("1000000.000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee does not have a default value"), - configbw(make_config([&](auto& c) { c.min_rent_fee = {}; }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), - configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("0.0000 TST"); }))); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_rent_fee must be positive"), - configbw(make_config([&](auto& c) { c.min_rent_fee = asset::from_string("-1.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_powerup_fee does not have a default value"), + configbw(make_config([&](auto& c) { c.min_powerup_fee = {}; }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_powerup_fee must be positive"), + configbw(make_config([&](auto& c) { c.min_powerup_fee = asset::from_string("0.0000 TST"); }))); + BOOST_REQUIRE_EQUAL(wasm_assert_msg("min_powerup_fee must be positive"), + configbw(make_config([&](auto& c) { c.min_powerup_fee = asset::from_string("-1.0000 TST"); }))); // net assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), - configbw(make_config([](auto& c) { c.net.current_weight_ratio = rentbw_frac + 1; }))); + configbw(make_config([](auto& c) { c.net.current_weight_ratio = powerup_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight/target_weight_ratio is too large"), configbw(make_config([](auto& c) { c.net.assumed_stake_weight = 100000; c.net.target_weight_ratio = 10; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), - configbw(make_config([](auto& c) { c.net.target_weight_ratio = rentbw_frac + 1; }))); + configbw(make_config([](auto& c) { c.net.target_weight_ratio = powerup_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight does not have a default value"), configbw(make_config([](auto& c) { c.net.assumed_stake_weight = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), @@ -318,14 +318,14 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { // cpu assertions BOOST_REQUIRE_EQUAL(wasm_assert_msg("current_weight_ratio is too large"), - configbw(make_config([](auto& c) { c.cpu.current_weight_ratio = rentbw_frac + 1; }))); + configbw(make_config([](auto& c) { c.cpu.current_weight_ratio = powerup_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight/target_weight_ratio is too large"), configbw(make_config([](auto& c) { c.cpu.assumed_stake_weight = 100000; c.cpu.target_weight_ratio = 10; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("weight can't grow over time"), - configbw(make_config([](auto& c) { c.cpu.target_weight_ratio = rentbw_frac + 1; }))); + configbw(make_config([](auto& c) { c.cpu.target_weight_ratio = powerup_frac + 1; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight does not have a default value"), configbw(make_config([](auto& c) { c.cpu.assumed_stake_weight = {}; }))); BOOST_REQUIRE_EQUAL(wasm_assert_msg("assumed_stake_weight must be at least 1; a much larger value is recommended"), @@ -363,15 +363,15 @@ BOOST_FIXTURE_TEST_CASE(config_tests, rentbw_tester) try { } // config_tests FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { +BOOST_FIXTURE_TEST_CASE(weight_tests, powerup_tester) try { produce_block(); - auto net_start = (rentbw_frac * 11) / 100; - auto net_target = (rentbw_frac * 1) / 100; - auto cpu_start = (rentbw_frac * 11) / 1000; - auto cpu_target = (rentbw_frac * 1) / 1000; + auto net_start = (powerup_frac * 11) / 100; + auto net_target = (powerup_frac * 1) / 100; + auto cpu_start = (powerup_frac * 11) / 1000; + auto cpu_target = (powerup_frac * 1) / 1000; - BOOST_REQUIRE_EQUAL("", configbw(make_config([&](rentbw_config& config) { + BOOST_REQUIRE_EQUAL("", configbw(make_config([&](powerup_config& config) { config.net.current_weight_ratio = net_start; config.net.target_weight_ratio = net_target; config.net.assumed_stake_weight = stake_weight; @@ -390,7 +390,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { auto state = get_state(); BOOST_REQUIRE(near( // state.net.weight_ratio, // - int64_t(state.net.assumed_stake_weight * eosio::chain::int128_t(rentbw_frac) / + int64_t(state.net.assumed_stake_weight * eosio::chain::int128_t(powerup_frac) / (state.net.weight + state.net.assumed_stake_weight)), 10)); }; @@ -402,7 +402,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { BOOST_REQUIRE_EQUAL("", configbw({})); } else if (i) { produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", powerupexec(config::system_account_name, 10)); } net = net_start + i * (net_target - net_start) / 10; cpu = cpu_start + i * (cpu_target - cpu_start) / 20; @@ -415,7 +415,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { { int i = 7; produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { config.net.target_timestamp = control->head_block_time() + fc::days(30); config.cpu.target_timestamp = control->head_block_time() + fc::days(40); }))); @@ -429,7 +429,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { for (int i = 0; i <= 5; ++i) { if (i) { produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", powerupexec(config::system_account_name, 10)); } net = net_start + i * (net_target - net_start) / 30; cpu = cpu_start + i * (cpu_target - cpu_start) / 40; @@ -444,7 +444,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { produce_block(fc::days(1) - fc::milliseconds(500)); auto new_net_target = net_target / 10; auto new_cpu_target = cpu_target / 20; - BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { config.net.target_weight_ratio = new_net_target; config.cpu.target_weight_ratio = new_cpu_target; }))); @@ -460,7 +460,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { for (int i = 0; i <= 10; ++i) { if (i) { produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", powerupexec(config::system_account_name, 10)); } net = net_start + i * (net_target - net_start) / (30 - 6); cpu = cpu_start + i * (cpu_target - cpu_start) / (40 - 6); @@ -472,7 +472,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { // Move transition time to immediate future { produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](rentbw_config& config) { + BOOST_REQUIRE_EQUAL("", configbw(make_default_config([&](powerup_config& config) { config.net.target_timestamp = control->head_block_time() + fc::milliseconds(1000); config.cpu.target_timestamp = control->head_block_time() + fc::milliseconds(1000); }))); @@ -481,7 +481,7 @@ BOOST_FIXTURE_TEST_CASE(weight_tests, rentbw_tester) try { // Verify targets hold as time advances for (int i = 0; i <= 10; ++i) { - BOOST_REQUIRE_EQUAL("", rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(get_state().net.weight_ratio, net_target, 1)); BOOST_REQUIRE(near(get_state().cpu.weight_ratio, cpu_target, 1)); check_weight(); @@ -492,50 +492,50 @@ FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_CASE(rent_tests) try { { - rentbw_tester t; + powerup_tester t; t.produce_block(); - BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("rentbw hasn't been initialized"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 4, rentbw_frac / 8, + BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("powerup hasn't been initialized"), // + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 4, powerup_frac / 8, asset::from_string("1.000 TST"))); BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { - config.net.current_weight_ratio = rentbw_frac; - config.net.target_weight_ratio = rentbw_frac; + config.net.current_weight_ratio = powerup_frac; + config.net.target_weight_ratio = powerup_frac; config.net.assumed_stake_weight = stake_weight; config.net.exponent = 1; config.net.min_price = asset::from_string("1000000.0000 TST"); config.net.max_price = asset::from_string("1000000.0000 TST"); - config.cpu.current_weight_ratio = rentbw_frac; - config.cpu.target_weight_ratio = rentbw_frac; + config.cpu.current_weight_ratio = powerup_frac; + config.cpu.target_weight_ratio = powerup_frac; config.cpu.assumed_stake_weight = stake_weight; config.cpu.exponent = 1; config.cpu.min_price = asset::from_string("1000000.0000 TST"); config.cpu.max_price = asset::from_string("1000000.0000 TST"); - config.rent_days = 30; - config.min_rent_fee = asset::from_string("1.0000 TST"); + config.powerup_days = 30; + config.min_powerup_fee = asset::from_string("1.0000 TST"); }))); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("max_payment doesn't match core symbol"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.000 TST"))); + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, powerup_frac, asset::from_string("1.000 TST"))); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("market doesn't have resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, 0, rentbw_frac, asset::from_string("1.0000 TST"))); + t.powerup(N(bob111111111), N(alice1111111), 30, 0, powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("market doesn't have resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, 0, asset::from_string("1.0000 TST"))); + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, 0, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL("", t.configbw(t.make_default_config([&](auto& config) { // weight = stake_weight - config.net.current_weight_ratio = rentbw_frac/2; - config.net.target_weight_ratio = rentbw_frac/2; + config.net.current_weight_ratio = powerup_frac/2; + config.net.target_weight_ratio = powerup_frac/2; // weight = stake_weight - config.cpu.current_weight_ratio = rentbw_frac/2; - config.cpu.target_weight_ratio = rentbw_frac/2; + config.cpu.current_weight_ratio = powerup_frac/2; + config.cpu.target_weight_ratio = powerup_frac/2; }))); auto net_weight = stake_weight; @@ -550,18 +550,18 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.2) * 1000000.0000 = 200000.0000 // total = 300000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("300000.0000")); - t.check_rentbw(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, rentbw_frac * .1, rentbw_frac * .2, + t.check_powerup(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, powerup_frac * .1, powerup_frac * .2, asset::from_string("300000.0000 TST"), net_weight * .1, cpu_weight * .2); // Start decay t.produce_block(fc::days(30) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, .1 * net_weight, 0)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, .2 * cpu_weight, 0)); // 2 days of decay from (10%, 20%) to (1.35%, 2.71%) t.produce_block(fc::days(2) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-2)), int64_t(.1 * net_weight * exp(-2)) / 1000)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(.2 * cpu_weight * exp(-2)), @@ -572,7 +572,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.02) * 1000000.0000 = 20000.0000 // total = 40000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("40000.0001")); - t.check_rentbw(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, rentbw_frac * .02, rentbw_frac * .02, + t.check_powerup(N(aaaaaaaaaaaa), N(aaaaaaaaaaaa), 30, powerup_frac * .02, powerup_frac * .02, asset::from_string("40000.0001 TST"), net_weight * .02, cpu_weight * .02); } @@ -580,21 +580,21 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { t.produce_block(); BOOST_REQUIRE_EQUAL("", t.configbw(t.make_config([&](auto& config) { // weight = stake_weight * 3 - config.net.current_weight_ratio = rentbw_frac / 4; - config.net.target_weight_ratio = rentbw_frac / 4; + config.net.current_weight_ratio = powerup_frac / 4; + config.net.target_weight_ratio = powerup_frac / 4; config.net.assumed_stake_weight = stake_weight; config.net.exponent = 2; config.net.max_price = asset::from_string("2000000.0000 TST"); // weight = stake_weight * 4 / 2 - config.cpu.current_weight_ratio = rentbw_frac / 5; - config.cpu.target_weight_ratio = rentbw_frac / 5; + config.cpu.current_weight_ratio = powerup_frac / 5; + config.cpu.target_weight_ratio = powerup_frac / 5; config.cpu.assumed_stake_weight = stake_weight / 2; config.cpu.exponent = 3; config.cpu.max_price = asset::from_string("6000000.0000 TST"); - config.rent_days = 30; - config.min_rent_fee = asset::from_string("1.0000 TST"); + config.powerup_days = 30; + config.min_powerup_fee = asset::from_string("1.0000 TST"); }))); if (rex) @@ -609,94 +609,94 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { auto cpu_weight = stake_weight * 4 / 2; { - rentbw_tester t; + powerup_tester t; init(t, false); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("days doesn't match configuration"), // - t.rentbw(N(bob111111111), N(alice1111111), 20, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); + t.powerup(N(bob111111111), N(alice1111111), 20, powerup_frac, powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("net_frac can't be negative"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, -rentbw_frac, rentbw_frac, + t.powerup(N(bob111111111), N(alice1111111), 30, -powerup_frac, powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("cpu_frac can't be negative"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, -rentbw_frac, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, -powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("net can't be more than 100%"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac + 1, rentbw_frac, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac + 1, powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("cpu can't be more than 100%"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac + 1, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, powerup_frac + 1, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("max_payment is less than calculated fee: 3000000.0000 TST"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, asset::from_string("1.0000 TST"))); + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, powerup_frac, asset::from_string("1.0000 TST"))); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("can't channel fees to rex"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac, rentbw_frac, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac, powerup_frac, asset::from_string("3000000.0000 TST"))); } // net:100%, cpu:100% { - rentbw_tester t; + powerup_tester t; init(t, true); t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); BOOST_REQUIRE_EQUAL( t.wasm_assert_msg("calculated fee is below minimum; try renting more"), - t.rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, 10, 10, asset::from_string("3000000.0000 TST"))); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + t.powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, 10, 10, asset::from_string("3000000.0000 TST"))); + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac, powerup_frac, asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("weight can't shrink below utilization"), t.configbw(t.make_default_config([&](auto& config) { - config.net.current_weight_ratio = rentbw_frac / 4 + 1; - config.net.target_weight_ratio = rentbw_frac / 4 + 1; - config.cpu.current_weight_ratio = rentbw_frac / 5; - config.cpu.target_weight_ratio = rentbw_frac / 5; + config.net.current_weight_ratio = powerup_frac / 4 + 1; + config.net.target_weight_ratio = powerup_frac / 4 + 1; + config.cpu.current_weight_ratio = powerup_frac / 5; + config.cpu.target_weight_ratio = powerup_frac / 5; }))); BOOST_REQUIRE_EQUAL( // t.wasm_assert_msg("weight can't shrink below utilization"), t.configbw(t.make_default_config([&](auto& config) { - config.net.current_weight_ratio = rentbw_frac / 4; - config.net.target_weight_ratio = rentbw_frac / 4; - config.cpu.current_weight_ratio = rentbw_frac / 5 + 1; - config.cpu.target_weight_ratio = rentbw_frac / 5 + 1; + config.net.current_weight_ratio = powerup_frac / 4; + config.net.target_weight_ratio = powerup_frac / 4; + config.cpu.current_weight_ratio = powerup_frac / 5 + 1; + config.cpu.target_weight_ratio = powerup_frac / 5 + 1; }))); BOOST_REQUIRE_EQUAL( // "", // t.configbw(t.make_default_config([&](auto& config) { - config.net.current_weight_ratio = rentbw_frac / 4; - config.net.target_weight_ratio = rentbw_frac / 4; - config.cpu.current_weight_ratio = rentbw_frac / 5; - config.cpu.target_weight_ratio = rentbw_frac / 5; + config.net.current_weight_ratio = powerup_frac / 4; + config.net.target_weight_ratio = powerup_frac / 4; + config.cpu.current_weight_ratio = powerup_frac / 5; + config.cpu.target_weight_ratio = powerup_frac / 5; }))); } // net:30%, cpu:40%, then net:5%, cpu:10% { - rentbw_tester t; + powerup_tester t; init(t, true); // (.3 ^ 2) * 2000000.0000 / 2 = 90000.0000 // (.4 ^ 3) * 6000000.0000 / 3 = 128000.0000 // total = 218000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("218000.0001")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .3, rentbw_frac * .4, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac * .3, powerup_frac * .4, asset::from_string("218000.0001 TST"), net_weight * .3, cpu_weight * .4); // (.35 ^ 2) * 2000000.0000 / 2 - 90000.0000 = 32500.0000 // (.5 ^ 3) * 6000000.0000 / 3 - 128000.0000 = 122000.0000 // total = 154500.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("154500.0000")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .05, rentbw_frac * .10, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac * .05, powerup_frac * .10, asset::from_string("154500.0000 TST"), net_weight * .05, cpu_weight * .10); } // net:50%, cpu:50% (but with non-zero min_price and also an exponent of 2 to simplify the math) { - rentbw_tester t; + powerup_tester t; init(t, true); BOOST_REQUIRE_EQUAL("", t.configbw(t.make_default_config([&](auto& config) { config.cpu.exponent = 2; @@ -726,29 +726,29 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // 4000000.0000 * .5 + (2000000.0000 / 2) * (.5 ^ 2) = 2250000.0000 // total = 2950000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("2950000.0000")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .5, rentbw_frac * .5, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac * .5, powerup_frac * .5, asset::from_string("2950000.0000 TST"), net_weight * .5, cpu_weight * .5); } { // net:100%, cpu:100% - rentbw_tester t; + powerup_tester t; init(t, true); t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac, powerup_frac, asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); // No more available for 30 days BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); t.produce_block(fc::days(29)); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); t.produce_block(fc::days(1) - fc::milliseconds(1500)); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); t.produce_block(fc::milliseconds(500)); @@ -758,32 +758,32 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (1.0 ^ 2) * 6000000.0000 = 6000000.0000 // total = 8000000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("8000000.0000")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac, powerup_frac, asset::from_string("8000000.0000 TST"), 0, 0); // No more available for 30 days BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); t.produce_block(fc::days(29)); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); t.produce_block(fc::days(1) - fc::milliseconds(1000)); BOOST_REQUIRE_EQUAL(t.wasm_assert_msg("market doesn't have enough resources available"), // - t.rentbw(N(bob111111111), N(alice1111111), 30, rentbw_frac / 1000, rentbw_frac / 1000, + t.powerup(N(bob111111111), N(alice1111111), 30, powerup_frac / 1000, powerup_frac / 1000, asset::from_string("1.0000 TST"))); // Start decay t.produce_block(fc::milliseconds(1000)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, net_weight, net_weight / 1000)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, cpu_weight, cpu_weight / 1000)); // 1 day of decay t.produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(net_weight * exp(-1)), int64_t(net_weight * exp(-1)) / 1000)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(cpu_weight * exp(-1)), @@ -791,7 +791,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // 1 day of decay t.produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, int64_t(net_weight * exp(-2)), int64_t(net_weight * exp(-2)) / 1000)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, int64_t(cpu_weight * exp(-2)), @@ -803,12 +803,12 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // [ ((e^-2) ^ 2)*(e^-2 - 0.0) + ((1.0) ^ 3)/3 - ((e^-2) ^ 3)/3 ] * 6000000.0000 = 2009915.0087 // total = 3028230.6476 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3028229.8795")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac, rentbw_frac, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac, powerup_frac, asset::from_string("3028229.8795 TST"), net_weight, cpu_weight); } { - rentbw_tester t; + powerup_tester t; init(t, true); // 10%, 20% @@ -816,7 +816,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.2 ^ 3) * 6000000.0000 / 3 = 16000.0000 // total = 26000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("26000.0002")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .1, rentbw_frac * .2, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac * .1, powerup_frac * .2, asset::from_string("26000.0002 TST"), net_weight * .1, cpu_weight * .2); t.produce_block(fc::days(15) - fc::milliseconds(500)); @@ -826,18 +826,18 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // (.4 ^ 3) * 6000000.0000 / 3 - 16000.0000 = 112000.0000 // total = 192000.0000 t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("192000.0001")); - t.check_rentbw(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, rentbw_frac * .2, rentbw_frac * .2, + t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac * .2, powerup_frac * .2, asset::from_string("192000.0001 TST"), net_weight * .2, cpu_weight * .2); // Start decay t.produce_block(fc::days(15) - fc::milliseconds(1000)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE(near(t.get_state().net.adjusted_utilization, .3 * net_weight, 0)); BOOST_REQUIRE(near(t.get_state().cpu.adjusted_utilization, .4 * cpu_weight, 0)); // 1 day of decay from (30%, 40%) to (20%, 20%) t.produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE( near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-1) + .2 * net_weight), 0)); BOOST_REQUIRE( @@ -845,7 +845,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { // 2 days of decay from (30%, 40%) to (20%, 20%) t.produce_block(fc::days(1) - fc::milliseconds(500)); - BOOST_REQUIRE_EQUAL("", t.rentbwexec(config::system_account_name, 10)); + BOOST_REQUIRE_EQUAL("", t.powerupexec(config::system_account_name, 10)); BOOST_REQUIRE( near(t.get_state().net.adjusted_utilization, int64_t(.1 * net_weight * exp(-2) + .2 * net_weight), 0)); BOOST_REQUIRE( From 280fe9eb8c3488b59a90c514b556b2d4ad38331e Mon Sep 17 00:00:00 2001 From: deck Date: Mon, 30 Nov 2020 12:13:03 -0500 Subject: [PATCH 71/78] Add configure and usage guide for powerup --- ...08_configure-use-powerup-resource-model.md | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 docs/04_guides/08_configure-use-powerup-resource-model.md diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md new file mode 100644 index 000000000..98eb17211 --- /dev/null +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -0,0 +1,248 @@ +# Configure and Use the `PowerUp` Resource Model + +## Configuration + +### Definitions + +#### Configuration +``` +// configure the `powerup` market. The market becomes available the first time this action is invoked +void cfgpowerup( powerup_config& args ); + +struct powerup_config_resource { + std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. // Do not specify to preserve the existing setting or use the default; + // this avoids sudden price jumps. For new chains which don't need + // to gradually phase out staking and REX, 0.01x (10^13) is a good + // value for both current_weight_ratio and target_weight_ratio. + std::optional target_weight_ratio; // Linearly shrink weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. + // Do not specify to preserve the existing setting or use the default. + std::optional assumed_stake_weight; // Assumed stake weight for ratio calculations. Use the sum of total + // staked and total rented by REX at the time the power market + // is first activated. Do not specify to preserve the existing + // setting (no default exists); this avoids sudden price jumps. + // For new chains which don't need to phase out staking and REX, + // 10^12 is probably a good value. + std::optional target_timestamp; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. Ignored + // if current_weight_ratio == target_weight_ratio. Do not specify + // this to preserve the existing setting (no default exists). + std::optional exponent; // Exponent of resource price curve. Must be >= 1. Do not specify + // to preserve the existing setting or use the default. + std::optional decay_secs; // Number of seconds for the gap between adjusted resource + // utilization and instantaneous resource utilization to shrink + // by 63%. Do not specify to preserve the existing setting or + // use the default. + std::optional min_price; // Fee needed to rent the entire resource market weight at the + // minimum price. For example, this could be set to 0.005% of + // total token supply. Do not specify to preserve the existing + // setting or use the default. + std::optional max_price; // Fee needed to rent the entire resource market weight at the + // maximum price. For example, this could be set to 10% of total + // token supply. Do not specify to preserve the existing + // setting (no default exists). + + }; + +struct powerup_config { + powerup_config_resource net; // NET market configuration + powerup_config_resource cpu; // CPU market configuration + std::optional powerup_days; // `power` `days` argument must match this. Do not specify to preserve the + // existing setting or use the default. + std::optional min_powerup_fee; // Rental fees below this amount are rejected. Do not specify to preserve the + // existing setting (no default exists). +}; +``` +#### State + +Definitions useful to help understand the configuration, including defaults: +``` +inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 + +struct powerup_state_resource { + static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a + // tiny amount of resources increases linearly + // with utilization. + static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a + // single loan, then, assuming no further renting, + // 1 day after it expires the adjusted utilization + // will be at approximately 37% and after 3 days + // the adjusted utilization will be less than 5%. + + uint8_t version = 0; + int64_t weight = 0; // resource market weight. calculated; varies over time. + // 1 represents the same amount of resources as 1 + // satoshi of SYS staked. + int64_t weight_ratio = 0; // resource market weight ratio: + // assumed_stake_weight / (assumed_stake_weight + weight). + // calculated; varies over time. 1x = 10^15. 0.01x = 10^13. + int64_t assumed_stake_weight = 0; // Assumed stake weight for ratio calculations. + int64_t initial_weight_ratio = powerup_frac; // Initial weight_ratio used for linear shrinkage. + int64_t target_weight_ratio = powerup_frac / 100; // Linearly shrink the weight_ratio to this amount. + time_point_sec initial_timestamp = {}; // When weight_ratio shrinkage started + time_point_sec target_timestamp = {}; // Stop automatic weight_ratio shrinkage at this time. Once this + // time hits, weight_ratio will be target_weight_ratio. + double exponent = default_exponent; // Exponent of resource price curve. + uint32_t decay_secs = default_decay_secs; // Number of seconds for the gap between adjusted resource + // utilization and instantaneous utilization to shrink by 63%. + asset min_price = {}; // Fee needed to rent the entire resource market weight at + // the minimum price (defaults to 0). + asset max_price = {}; // Fee needed to rent the entire resource market weight at + // the maximum price. + int64_t utilization = 0; // Instantaneous resource utilization. This is the current + // amount sold. utilization <= weight. + int64_t adjusted_utilization = 0; // Adjusted resource utilization. This is >= utilization and + // <= weight. It grows instantly but decays exponentially. + time_point_sec utilization_timestamp = {}; // When adjusted_utilization was last updated +}; + +struct powerup_state { + static constexpr uint32_t default_powerup_days = 30; // 30 day resource powerups + + uint8_t version = 0; + powerup_state_resource net = {}; // NET market state + powerup_state_resource cpu = {}; // CPU market state + uint32_t powerup_days = default_powerup_days; // `powerup` `days` argument must match this. + asset min_powerup_fee = {}; // fees below this amount are rejected + + uint64_t primary_key()const { return 0; } +}; +``` + +### Preparation for Upgrade +1. Build [eosio.contracts](https://github.com/EOSIO/eosio.contracts) with `powerup` code. Version **1.9.2** or greater . +2. Deploy eosio.system contract to `eosio`. +3. Create account `eosio.reserv` and ensure the account has enough at least 4 KiB of RAM. +4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. +5. Enable the REX system (if not enabled). + +### Configuring `PowerUp` + +#### Config file +``` +# config.json +{ + "net": { + "assumed_stake_weight": 944076307, + "current_weight_ratio": 1000000000000000, + "decay_secs": 86400, + "exponent": 2, + "max_price": "10000000.0000 TST", + "min_price": "0.0000 TST", + "target_timestamp": "2022-01-01T00:00:00.000", + "target_weight_ratio": 10000000000000 + }, + "cpu": { + "assumed_stake_weight": 3776305228, + "current_weight_ratio": 1000000000000000, + "decay_secs": 86400, + "exponent": 2, + "max_price": "10000000.0000 TST", + "min_price": "0.0000 TST", + "target_timestamp": "2022-01-01T00:00:00.000", + "target_weight_ratio": 10000000000000 + }, + "min_powerup_fee": "0.0001 TST", + "powerup_days": 1 +} +``` + +#### `cfgpowerup` Action Call +``` +# call to `cfgpowerup` +cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio +``` + +#### Check state +``` +cleos get table eosio 0 powup.state +{ + "rows": [{ + "version": 0, + "net": { + "version": 0, + "weight": 0, + "weight_ratio": "1000000000000000", + "assumed_stake_weight": 944076307, + "initial_weight_ratio": "1000000000000000", + "target_weight_ratio": "10000000000000", + "initial_timestamp": "2020-11-16T19:52:50", + "target_timestamp": "2022-01-01T00:00:00", + "exponent": "2.00000000000000000", + "decay_secs": 3600, + "min_price": "0.0000 EOS", + "max_price": "10000000.0000 EOS", + "utilization": 0, + "adjusted_utilization": 0, + "utilization_timestamp": "2020-11-16T19:52:50" + }, + "cpu": { + "version": 0, + "weight": 0, + "weight_ratio": "1000000000000000", + "assumed_stake_weight": 3776305228, + "initial_weight_ratio": "1000000000000000", + "target_weight_ratio": "10000000000000", + "initial_timestamp": "2020-11-16T19:52:50", + "target_timestamp": "2022-01-01T00:00:00", + "exponent": "2.00000000000000000", + "decay_secs": 3600, + "min_price": "0.0000 EOS", + "max_price": "10000000.0000 EOS", + "utilization": 0, + "adjusted_utilization": 0, + "utilization_timestamp": "2020-11-16T19:52:50" + }, + "powerup_days": 1, + "min_powerup_fee": "0.0001 EOS" + } + ], + "more": false, + "next_key": "" +} +``` + +### Using `PowerUp` + +#### Executing an order +The action to powerup an account is `powerup`. It takes a `payer` and a `receiver` of the resources. The `days` should always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 1% = 10^13. +``` +cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user +executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us +# eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... +# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 EOS","powup_net":"1.6354 EOS","powup_cpu":"6.5416 EOS"} +# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +``` +You can see how many tokens were received for `NET` and `CPU` as well as the fee by looking at the `eosio.reserv::powupresult` informational action. + +*It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* + +#### Clearing the orders queue + +The orders table `powup.order` can be viewed by calling: +``` +cleos get table eosio 0 powup.order +{ + "rows": [{ + "version": 0, + "id": 0, + "owner": "user", + "net_weight": 16354, + "cpu_weight": 65416, + "expires": "2020-11-18T13:04:33" + } + ], + "more": false, + "next_key": "" +} +``` + +The action `powerupexec` that takes a `name` of a user and the `max` number of orders that will be cleared if expired. It is worth noting that the call to `powerup` will also clear up to two expired orders per call. + +``` +cleos push action eosio powerupexec '[user, 2]' -p user +executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us +# eosio <= eosio::powerupexec {"user":"user","max":2} +warning: transaction executed locally, but may not be confirmed by the network yet ] +``` \ No newline at end of file From b17f0d3a5975bcdd8bed68bb27303f42fecaef2f Mon Sep 17 00:00:00 2001 From: deck Date: Mon, 30 Nov 2020 14:18:03 -0500 Subject: [PATCH 72/78] add back a comment removed in error --- contracts/eosio.system/src/powerup.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/eosio.system/src/powerup.cpp b/contracts/eosio.system/src/powerup.cpp index ebab2615b..fd32a9dd3 100644 --- a/contracts/eosio.system/src/powerup.cpp +++ b/contracts/eosio.system/src/powerup.cpp @@ -279,6 +279,8 @@ int64_t calc_powerup_fee(const powerup_state_resource& state, int64_t utilizatio coefficient * std::pow(end_u, state.exponent) - coefficient * std::pow(start_u, state.exponent); }; + // Returns p(double(utilization)/state.weight). + // @pre 0 <= utilization <= state.weight auto price_function = [&state](int64_t utilization) -> double { double price = state.min_price.amount; // state.exponent >= 1.0, therefore the exponent passed into std::pow is >= 0.0. From 065e865d67f5d0e598ba8017503903e6980bbbfa Mon Sep 17 00:00:00 2001 From: deck Date: Tue, 1 Dec 2020 09:11:14 -0500 Subject: [PATCH 73/78] Removing the word `rent` from comments/error messages. Fixing some minor typos and comment blocks. Change `process_queue` to a more definitive `process_powerup_queue`. --- .../include/eosio.system/eosio.system.hpp | 28 +++++++++---------- .../include/eosio.system/powerup.results.hpp | 4 +-- contracts/eosio.system/src/powerup.cpp | 10 +++---- ...08_configure-use-powerup-resource-model.md | 16 +++++------ tests/eosio.powerup_tests.cpp | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index a70726f18..d49834cdb 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -549,11 +549,11 @@ namespace eosiosystem { // utilization and instantaneous resource utilization to shrink // by 63%. Do not specify to preserve the existing setting or // use the default. - std::optional min_price; // Fee needed to rent the entire resource market weight at the + std::optional min_price; // Fee needed to reserve the entire resource market weight at the // minimum price. For example, this could be set to 0.005% of // total token supply. Do not specify to preserve the existing // setting or use the default. - std::optional max_price; // Fee needed to rent the entire resource market weight at the + std::optional max_price; // Fee needed to reserve the entire resource market weight at the // maximum price. For example, this could be set to 10% of total // token supply. Do not specify to preserve the existing // setting (no default exists). @@ -563,22 +563,22 @@ namespace eosiosystem { }; struct powerup_config { - powerup_config_resource net; // NET market configuration - powerup_config_resource cpu; // CPU market configuration - std::optional powerup_days; // `power` `days` argument must match this. Do not specify to preserve the - // existing setting or use the default. - std::optional min_powerup_fee; // Rental fees below this amount are rejected. Do not specify to preserve the - // existing setting (no default exists). + powerup_config_resource net; // NET market configuration + powerup_config_resource cpu; // CPU market configuration + std::optional powerup_days; // `powerup` `days` argument must match this. Do not specify to preserve the + // existing setting or use the default. + std::optional min_powerup_fee; // Fees below this amount are rejected. Do not specify to preserve the + // existing setting (no default exists). EOSLIB_SERIALIZE( powerup_config, (net)(cpu)(powerup_days)(min_powerup_fee) ) }; struct powerup_state_resource { - static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a + static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to reserve a // tiny amount of resources increases linearly // with utilization. static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a - // single loan, then, assuming no further renting, + // single loan, then, assuming no further powerup usage, // 1 day after it expires the adjusted utilization // will be at approximately 37% and after 3 days // the adjusted utilization will be less than 5%. @@ -599,9 +599,9 @@ namespace eosiosystem { double exponent = default_exponent; // Exponent of resource price curve. uint32_t decay_secs = default_decay_secs; // Number of seconds for the gap between adjusted resource // utilization and instantaneous utilization to shrink by 63%. - asset min_price = {}; // Fee needed to rent the entire resource market weight at + asset min_price = {}; // Fee needed to reserve the entire resource market weight at // the minimum price (defaults to 0). - asset max_price = {}; // Fee needed to rent the entire resource market weight at + asset max_price = {}; // Fee needed to reserve the entire resource market weight at // the maximum price. int64_t utilization = 0; // Instantaneous resource utilization. This is the current // amount sold. utilization <= weight. @@ -1315,7 +1315,7 @@ namespace eosiosystem { void powerupexec( const name& user, uint16_t max ); /** - * Rent NET and CPU by percentage + * Powerup NET and CPU resources by percentage * * @param payer - the resource buyer * @param receiver - the resource receiver @@ -1480,7 +1480,7 @@ namespace eosiosystem { // defined in power.cpp void adjust_resources(name payer, name account, symbol core_symbol, int64_t net_delta, int64_t cpu_delta, bool must_not_be_managed = false); - void process_queue( + void process_powerup_queue( time_point_sec now, symbol core_symbol, powerup_state& state, powerup_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available); diff --git a/contracts/eosio.system/include/eosio.system/powerup.results.hpp b/contracts/eosio.system/include/eosio.system/powerup.results.hpp index 52d86cd12..d29ec87dc 100644 --- a/contracts/eosio.system/include/eosio.system/powerup.results.hpp +++ b/contracts/eosio.system/include/eosio.system/powerup.results.hpp @@ -10,7 +10,7 @@ using eosio::name; /** * The action `powerresult` of `power.results` is a no-op. - * It is added as an inline convenience action to `power` rental. + * It is added as an inline convenience action to `powerup` reservation. * This inline convenience action does not have any effect, however, * its data includes the result of the parent action and appears in its trace. */ @@ -22,7 +22,7 @@ class [[eosio::contract("powup.results")]] powup_results : eosio::contract { /** * powupresult action. * - * @param fee - rental fee amount + * @param fee - powerup fee amount * @param powup_net - amount of powup NET tokens * @param powup_cpu - amount of powup CPU tokens */ diff --git a/contracts/eosio.system/src/powerup.cpp b/contracts/eosio.system/src/powerup.cpp index fd32a9dd3..614d6745a 100644 --- a/contracts/eosio.system/src/powerup.cpp +++ b/contracts/eosio.system/src/powerup.cpp @@ -67,7 +67,7 @@ void system_contract::adjust_resources(name payer, name account, symbol core_sym } } // system_contract::adjust_resources -void system_contract::process_queue(time_point_sec now, symbol core_symbol, powerup_state& state, +void system_contract::process_powerup_queue(time_point_sec now, symbol core_symbol, powerup_state& state, powerup_order_table& orders, uint32_t max_items, int64_t& net_delta_available, int64_t& cpu_delta_available) { update_utilization(now, state.net); @@ -325,7 +325,7 @@ void system_contract::powerupexec(const name& user, uint16_t max) { int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - process_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); + process_powerup_queue(now, core_symbol, state, orders, max, net_delta_available, cpu_delta_available); adjust_resources(get_self(), reserv_account, core_symbol, net_delta_available, cpu_delta_available, true); state_sing.set(state, get_self()); @@ -349,7 +349,7 @@ void system_contract::powerup(const name& payer, const name& receiver, uint32_t int64_t net_delta_available = 0; int64_t cpu_delta_available = 0; - process_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); + process_powerup_queue(now, core_symbol, state, orders, 2, net_delta_available, cpu_delta_available); eosio::asset fee{ 0, core_symbol }; auto process = [&](int64_t frac, int64_t& amount, powerup_state_resource& state) { @@ -359,7 +359,7 @@ void system_contract::powerup(const name& payer, const name& receiver, uint32_t eosio::check(state.weight, "market doesn't have resources available"); eosio::check(state.utilization + amount <= state.weight, "market doesn't have enough resources available"); int64_t f = calc_powerup_fee(state, amount); - eosio::check(f > 0, "calculated fee is below minimum; try renting more"); + eosio::check(f > 0, "calculated fee is below minimum; try powering up with more resources"); fee.amount += f; state.utilization += amount; }; @@ -373,7 +373,7 @@ void system_contract::powerup(const name& payer, const name& receiver, uint32_t error_msg += fee.to_string(); eosio::check(false, error_msg); } - eosio::check(fee >= state.min_powerup_fee, "calculated fee is below minimum; try renting more"); + eosio::check(fee >= state.min_powerup_fee, "calculated fee is below minimum; try powering up with more resources"); orders.emplace(payer, [&](auto& order) { order.id = orders.available_primary_key(); diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 98eb17211..5597acb46 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -32,11 +32,11 @@ struct powerup_config_resource { // utilization and instantaneous resource utilization to shrink // by 63%. Do not specify to preserve the existing setting or // use the default. - std::optional min_price; // Fee needed to rent the entire resource market weight at the + std::optional min_price; // Fee needed to reserve the entire resource market weight at the // minimum price. For example, this could be set to 0.005% of // total token supply. Do not specify to preserve the existing // setting or use the default. - std::optional max_price; // Fee needed to rent the entire resource market weight at the + std::optional max_price; // Fee needed to reserve the entire resource market weight at the // maximum price. For example, this could be set to 10% of total // token supply. Do not specify to preserve the existing // setting (no default exists). @@ -46,9 +46,9 @@ struct powerup_config_resource { struct powerup_config { powerup_config_resource net; // NET market configuration powerup_config_resource cpu; // CPU market configuration - std::optional powerup_days; // `power` `days` argument must match this. Do not specify to preserve the + std::optional powerup_days; // `powerup` `days` argument must match this. Do not specify to preserve the // existing setting or use the default. - std::optional min_powerup_fee; // Rental fees below this amount are rejected. Do not specify to preserve the + std::optional min_powerup_fee; // Powerup fees below this amount are rejected. Do not specify to preserve the // existing setting (no default exists). }; ``` @@ -59,11 +59,11 @@ Definitions useful to help understand the configuration, including defaults: inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 struct powerup_state_resource { - static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to rent a + static constexpr double default_exponent = 2.0; // Exponent of 2.0 means that the price to reserve a // tiny amount of resources increases linearly // with utilization. static constexpr uint32_t default_decay_secs = 1 * seconds_per_day; // 1 day; if 100% of bandwidth resources are in a - // single loan, then, assuming no further renting, + // single loan, then, assuming no further powerup usage, // 1 day after it expires the adjusted utilization // will be at approximately 37% and after 3 days // the adjusted utilization will be less than 5%. @@ -84,9 +84,9 @@ struct powerup_state_resource { double exponent = default_exponent; // Exponent of resource price curve. uint32_t decay_secs = default_decay_secs; // Number of seconds for the gap between adjusted resource // utilization and instantaneous utilization to shrink by 63%. - asset min_price = {}; // Fee needed to rent the entire resource market weight at + asset min_price = {}; // Fee needed to reserve the entire resource market weight at // the minimum price (defaults to 0). - asset max_price = {}; // Fee needed to rent the entire resource market weight at + asset max_price = {}; // Fee needed to reserve the entire resource market weight at // the maximum price. int64_t utilization = 0; // Instantaneous resource utilization. This is the current // amount sold. utilization <= weight. diff --git a/tests/eosio.powerup_tests.cpp b/tests/eosio.powerup_tests.cpp index fa12fc073..3c8f43e0f 100644 --- a/tests/eosio.powerup_tests.cpp +++ b/tests/eosio.powerup_tests.cpp @@ -644,7 +644,7 @@ BOOST_AUTO_TEST_CASE(rent_tests) try { init(t, true); t.transfer(config::system_account_name, N(aaaaaaaaaaaa), core_sym::from_string("3000000.0000")); BOOST_REQUIRE_EQUAL( - t.wasm_assert_msg("calculated fee is below minimum; try renting more"), + t.wasm_assert_msg("calculated fee is below minimum; try powering up with more resources"), t.powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, 10, 10, asset::from_string("3000000.0000 TST"))); t.check_powerup(N(aaaaaaaaaaaa), N(bbbbbbbbbbbb), 30, powerup_frac, powerup_frac, asset::from_string("3000000.0000 TST"), net_weight, cpu_weight); From 0992ba3556b216bd41acfad191265cd18ed78f5b Mon Sep 17 00:00:00 2001 From: deck Date: Tue, 1 Dec 2020 10:38:19 -0500 Subject: [PATCH 74/78] Correctly provide weight over the asset received. This will be more useful information to the users. --- contracts/eosio.system/include/eosio.system/powerup.results.hpp | 2 +- contracts/eosio.system/src/powerup.cpp | 2 +- contracts/eosio.system/src/powerup.results.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/powerup.results.hpp b/contracts/eosio.system/include/eosio.system/powerup.results.hpp index d29ec87dc..716be93a0 100644 --- a/contracts/eosio.system/include/eosio.system/powerup.results.hpp +++ b/contracts/eosio.system/include/eosio.system/powerup.results.hpp @@ -27,7 +27,7 @@ class [[eosio::contract("powup.results")]] powup_results : eosio::contract { * @param powup_cpu - amount of powup CPU tokens */ [[eosio::action]] - void powupresult( const asset& fee, const asset& powup_net, const asset& powup_cpu ); + void powupresult( const asset& fee, const int64_t powup_net, const int64_t powup_cpu ); using powupresult_action = action_wrapper<"powupresult"_n, &powup_results::powupresult>; }; diff --git a/contracts/eosio.system/src/powerup.cpp b/contracts/eosio.system/src/powerup.cpp index 614d6745a..335d9bb23 100644 --- a/contracts/eosio.system/src/powerup.cpp +++ b/contracts/eosio.system/src/powerup.cpp @@ -392,7 +392,7 @@ void system_contract::powerup(const name& payer, const name& receiver, uint32_t // inline noop action powup_results::powupresult_action powupresult_act{ reserv_account, std::vector{ } }; - powupresult_act.send( fee, asset{ net_amount, core_symbol }, asset{ cpu_amount, core_symbol } ); + powupresult_act.send( fee, net_amount, cpu_amount ); } } // namespace eosiosystem diff --git a/contracts/eosio.system/src/powerup.results.cpp b/contracts/eosio.system/src/powerup.results.cpp index 7b9c80269..2be2e981a 100644 --- a/contracts/eosio.system/src/powerup.results.cpp +++ b/contracts/eosio.system/src/powerup.results.cpp @@ -1,5 +1,5 @@ #include -void powup_results::powupresult( const asset& fee, const asset& powup_net, const asset& powup_cpu ) { } +void powup_results::powupresult( const asset& fee, const int64_t powup_net_weight, const int64_t powup_cpu_weight ) { } extern "C" void apply( uint64_t, uint64_t, uint64_t ) { } From c357f9ba547fdbb73d081bee1bd07364fcb85f37 Mon Sep 17 00:00:00 2001 From: deck Date: Wed, 2 Dec 2020 10:25:56 -0500 Subject: [PATCH 75/78] Add an Overview and Processing Expired Orders section. --- ...08_configure-use-powerup-resource-model.md | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 5597acb46..82eb41b4b 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -1,5 +1,14 @@ # Configure and Use the `PowerUp` Resource Model +## Overview +This new system will create a new optional NET and CPU rental market which displaces (over time) +the existing staking system and REX market. Under the old model, system token holders +own NET and CPU and may choose to use it themselves, delegate it to others, or make +it available for others to rent using the REX market. Under this new model, the chain +owns almost all NET and CPU resources and the only way to access these resources is +through the new `powerup` action. It channels fees to the REX pool to enable token holders +to profit off the new market. + ## Configuration ### Definitions @@ -109,9 +118,9 @@ struct powerup_state { ``` ### Preparation for Upgrade -1. Build [eosio.contracts](https://github.com/EOSIO/eosio.contracts) with `powerup` code. Version **1.9.2** or greater . +1. Build [eosio.contracts](https://github.com/EOSIO/eosio.contracts) with `powerup` code. Version **1.9.x** or greater . 2. Deploy eosio.system contract to `eosio`. -3. Create account `eosio.reserv` and ensure the account has enough at least 4 KiB of RAM. +3. Create account `eosio.reserv` and ensure the account has enough RAM, at least 4 KiB. 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. 5. Enable the REX system (if not enabled). @@ -169,8 +178,8 @@ cleos get table eosio 0 powup.state "target_timestamp": "2022-01-01T00:00:00", "exponent": "2.00000000000000000", "decay_secs": 3600, - "min_price": "0.0000 EOS", - "max_price": "10000000.0000 EOS", + "min_price": "0.0000 TST", + "max_price": "10000000.0000 TST", "utilization": 0, "adjusted_utilization": 0, "utilization_timestamp": "2020-11-16T19:52:50" @@ -186,14 +195,14 @@ cleos get table eosio 0 powup.state "target_timestamp": "2022-01-01T00:00:00", "exponent": "2.00000000000000000", "decay_secs": 3600, - "min_price": "0.0000 EOS", - "max_price": "10000000.0000 EOS", + "min_price": "0.0000 TST", + "max_price": "10000000.0000 TST", "utilization": 0, "adjusted_utilization": 0, "utilization_timestamp": "2020-11-16T19:52:50" }, "powerup_days": 1, - "min_powerup_fee": "0.0001 EOS" + "min_powerup_fee": "0.0001 TST" } ], "more": false, @@ -204,21 +213,22 @@ cleos get table eosio 0 powup.state ### Using `PowerUp` #### Executing an order -The action to powerup an account is `powerup`. It takes a `payer` and a `receiver` of the resources. The `days` should always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 1% = 10^13. +The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. ``` -cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 EOS"]' -p user +cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... -# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} -# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 EOS","powup_net":"1.6354 EOS","powup_cpu":"6.5416 EOS"} -# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} -# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 EOS","memo":"transfer from user to eosio.rex"} +# eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +# eosio.reserv <= eosio.reserv::powupresult {"fee":"999.9901 TST","powup_net_weight":"16354","powup_cpu_weight":"65416"} +# user <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} +# eosio.rex <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} ``` -You can see how many tokens were received for `NET` and `CPU` as well as the fee by looking at the `eosio.reserv::powupresult` informational action. +You can see how much NET and CPU weight was received as well as the fee by looking at the `eosio.reserv::powupresult` informational action. *It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* -#### Clearing the orders queue +#### Processing Expired Orders +The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make rental prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. The orders table `powup.order` can be viewed by calling: ``` @@ -238,7 +248,7 @@ cleos get table eosio 0 powup.order } ``` -The action `powerupexec` that takes a `name` of a user and the `max` number of orders that will be cleared if expired. It is worth noting that the call to `powerup` will also clear up to two expired orders per call. +Example `powerupexec` call: ``` cleos push action eosio powerupexec '[user, 2]' -p user From ce5588b5abf1b5d6201bb7bcbd4e450024022421 Mon Sep 17 00:00:00 2001 From: deck Date: Wed, 2 Dec 2020 13:50:08 -0500 Subject: [PATCH 76/78] Remove some rental language. --- docs/04_guides/08_configure-use-powerup-resource-model.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 82eb41b4b..7b39ee838 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -1,7 +1,7 @@ # Configure and Use the `PowerUp` Resource Model ## Overview -This new system will create a new optional NET and CPU rental market which displaces (over time) +This new system will create a new optional NET and CPU marketplace which displaces (over time) the existing staking system and REX market. Under the old model, system token holders own NET and CPU and may choose to use it themselves, delegate it to others, or make it available for others to rent using the REX market. Under this new model, the chain @@ -228,7 +228,7 @@ You can see how much NET and CPU weight was received as well as the fee by looki *It is worth mentioning that the network being used for the example has not fully transitioned so the available resources are minimal therefore 1% of the resources are quite expensive. As the system continues the transition more resources are available to the `PowerUp` resource model and will become more affordable.* #### Processing Expired Orders -The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make rental prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. +The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. The orders table `powup.order` can be viewed by calling: ``` From 4fce5daaebcdb5d1299cca9a921178e18079bd8a Mon Sep 17 00:00:00 2001 From: deck Date: Tue, 8 Dec 2020 08:54:29 -0500 Subject: [PATCH 77/78] update powerup config/install docs --- ...08_configure-use-powerup-resource-model.md | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/docs/04_guides/08_configure-use-powerup-resource-model.md b/docs/04_guides/08_configure-use-powerup-resource-model.md index 7b39ee838..35a6c9339 100644 --- a/docs/04_guides/08_configure-use-powerup-resource-model.md +++ b/docs/04_guides/08_configure-use-powerup-resource-model.md @@ -1,4 +1,8 @@ -# Configure and Use the `PowerUp` Resource Model +--- +content_title: How to configure PowerUp resource model +link_text: How to configure PowerUp resource model +--- +# Configure and Use the PowerUp Resource Model ## Overview This new system will create a new optional NET and CPU marketplace which displaces (over time) @@ -14,12 +18,13 @@ to profit off the new market. ### Definitions #### Configuration -``` +```c++ // configure the `powerup` market. The market becomes available the first time this action is invoked void cfgpowerup( powerup_config& args ); struct powerup_config_resource { - std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. // Do not specify to preserve the existing setting or use the default; + std::optional current_weight_ratio; // Immediately set weight_ratio to this amount. 1x = 10^15. 0.01x = 10^13. + // Do not specify to preserve the existing setting or use the default; // this avoids sudden price jumps. For new chains which don't need // to gradually phase out staking and REX, 0.01x (10^13) is a good // value for both current_weight_ratio and target_weight_ratio. @@ -64,7 +69,7 @@ struct powerup_config { #### State Definitions useful to help understand the configuration, including defaults: -``` +```c++ inline constexpr int64_t powerup_frac = 1'000'000'000'000'000ll; // 1.0 = 10^15 struct powerup_state_resource { @@ -124,10 +129,10 @@ struct powerup_state { 4. Deploy `powup.results.abi` to `eosio.reserv` account using `setabi`. The ABI can be found in the `build/contracts/eosio.system/.powerup/` directory. 5. Enable the REX system (if not enabled). -### Configuring `PowerUp` +### Configuring PowerUp #### Config file -``` +```json # config.json { "net": { @@ -155,15 +160,17 @@ struct powerup_state { } ``` -#### `cfgpowerup` Action Call -``` +#### cfgpowerup Action Call +```sh # call to `cfgpowerup` cleos push action eosio cfgpowerup "[`cat ./config.json`]" -p eosio ``` #### Check state -``` +```sh cleos get table eosio 0 powup.state +``` +```json { "rows": [{ "version": 0, @@ -210,12 +217,14 @@ cleos get table eosio 0 powup.state } ``` -### Using `PowerUp` +### Using PowerUp #### Executing an order The action to power up an account is `powerup`. It takes a `payer` of the fee and a `receiver` of the resources. The `days` must always match `state.powerup_days`. `net_frac` and `cpu_frac` are the percentage of the resources that you need. The easiest way to caclulate the percentage is to multiple 10^15 (100%) by the desired percentage. For example: 10^15 * 0.01 = 10^13. -``` +```sh cleos push action eosio powerup '[user, user, 1, 10000000000000, 10000000000000, "1000.0000 TST"]' -p user +``` +``` executed transaction: 82b7124601612b371b812e3bf65cf63bb44616802d3cd33a2c0422b58399f54f 144 bytes 521 us # eosio <= eosio::powerup {"payer":"user","receiver":"user","days":1,"net_frac":"10000000000000","cpu_frac":"10000000000000","... # eosio.token <= eosio.token::transfer {"from":"user","to":"eosio.rex","quantity":"999.9901 TST","memo":"transfer from user to eosio.rex"} @@ -231,8 +240,10 @@ You can see how much NET and CPU weight was received as well as the fee by looki The resources in loans that expire do not automatically get reclaimed by the system. The expired loans sit in a queue that must be processed. Anyone calling the `powerup` action will help with processing this queue (limited to processing at most two expired loans at a time) so that normally the expired loans will be automatically processed in a timely manner. However, in some cases it may be necessary to manual process expired loans in the queue to make resources available to the system again and thus make prices cheaper. In such a scenario, any account may process up to an arbitrary number of expired loans by calling the `powerupexec` action. The orders table `powup.order` can be viewed by calling: -``` +```sh cleos get table eosio 0 powup.order +``` +```json { "rows": [{ "version": 0, @@ -250,8 +261,10 @@ cleos get table eosio 0 powup.order Example `powerupexec` call: -``` +```sh cleos push action eosio powerupexec '[user, 2]' -p user +``` +```console executed transaction: 93ab4ac900a7902e4e59e5e925e8b54622715328965150db10774aa09855dc98 104 bytes 363 us # eosio <= eosio::powerupexec {"user":"user","max":2} warning: transaction executed locally, but may not be confirmed by the network yet ] From 5fdce694439d18f0789f3bb2100391cc288f03fb Mon Sep 17 00:00:00 2001 From: deck Date: Wed, 16 Dec 2020 09:28:47 -0500 Subject: [PATCH 78/78] Bump version to v1.9.2 --- CMakeLists.txt | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index adbdce0ae..7ddd2b135 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 9) -set(VERSION_PATCH 1) +set(VERSION_PATCH 2) #set(VERSION_SUFFIX rc4) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index 21ecb6328..cb90a374d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.9.1 +## Version : 1.9.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. @@ -16,7 +16,7 @@ The following unprivileged contract(s) are also part of the system. Dependencies: * [eosio.cdt v1.7.x](https://github.com/EOSIO/eosio.cdt/releases/tag/v1.7.0) -* [eosio v2.0.x](https://github.com/EOSIO/eos/releases/tag/v2.0.1) (optional dependency only needed to build unit tests) +* [eosio v2.0.x](https://github.com/EOSIO/eos/releases/tag/v2.0.8) (optional dependency only needed to build unit tests) ## Build