From 1029e1df4c6c465d065a236778d85ef68bdbb3a2 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 13 Nov 2019 17:16:53 -0500 Subject: [PATCH 01/24] REX changes - initial commit --- .../include/eosio.system/eosio.system.hpp | 14 ++++++ contracts/eosio.system/src/eosio.system.cpp | 2 +- contracts/eosio.system/src/rex.cpp | 50 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index a952edd98..2cc9d0c92 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -333,6 +333,17 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; + struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { + uint8_t version = 0; + int64_t current_rate_of_increase = 0; + time_point_sec last_update_time; + std::map return_buckets; + + uint64_t primary_key()const { return 0; } + }; + + typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + // `rex_fund` structure underlying the rex fund table. A rex fund table entry is defined by: // - `version` defaulted to zero, // - `owner` the owner of the rex fund, @@ -443,6 +454,7 @@ namespace eosiosystem { eosio_global_state4 _gstate4; rammarket _rammarket; rex_pool_table _rexpool; + rex_return_pool_table _rexretpool; rex_fund_table _rexfunds; rex_balance_table _rexbalance; rex_order_table _rexorders; @@ -1121,6 +1133,7 @@ namespace eosiosystem { // defined in rex.cpp void runrex( uint16_t max ); + void update_rex_pool(); void update_resource_limits( const name& from, const name& receiver, int64_t delta_net, int64_t delta_cpu ); void check_voting_requirement( const name& owner, const char* error_msg = "must vote for at least 21 producers or for a proxy before buying REX" )const; @@ -1142,6 +1155,7 @@ namespace eosiosystem { static time_point_sec get_rex_maturity(); asset add_to_rex_balance( const name& owner, const asset& payment, const asset& rex_received ); asset add_to_rex_pool( const asset& payment ); + void add_to_rex_return_pool( const asset& fee ); void process_rex_maturities( const rex_balance_table::const_iterator& bitr ); void consolidate_rex_balance( const rex_balance_table::const_iterator& bitr, const asset& rex_in_sell_order ); diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index b05c5f011..a6af9e0d0 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -26,11 +26,11 @@ namespace eosiosystem { _global4(get_self(), get_self().value), _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), + _rexretpool(get_self(), get_self().value), _rexfunds(get_self(), get_self().value), _rexbalance(get_self(), get_self().value), _rexorders(get_self(), get_self().value) { - //print( "construct system\n" ); _gstate = _global.exists() ? _global.get() : get_default_parameters(); _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 4a4596e25..c55c798ab 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -513,6 +513,8 @@ namespace eosiosystem { { check( rex_system_initialized(), "rex system not initialized yet" ); + update_rex_pool(); + const auto& pool = _rexpool.begin(); auto process_expired_loan = [&]( auto& idx, const auto& itr ) -> std::pair { @@ -616,6 +618,43 @@ namespace eosiosystem { } + void system_contract::update_rex_pool() + { + const int32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); + const auto time_threshold = ct - eosio::days(num_of_days); + + int64_t change = change_estimate; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + auto& return_buckets = return_pool.return_buckets; + auto iter= return_buckets.begin(); + while ( iter!= return_buckets.begin() && iter->first <= time_threshold ) { + auto next = iter; + ++next; + const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); + const int64_t rate = iter->second; + int64_t surplus = ( uint128_t(overtime) * rate ) / ( num_of_days * seconds_per_day ); + change -= surplus; + return_pool.current_rate_of_increase -= rate; + return_buckets.erase(iter); + iter = next; + } + return_pool.last_update_time = ct; + }); + + if ( change <= 0 ) { + return; + } + + _rexpool.modify(_rexpool.begin(), same_payer, [&](auto& pool) { + pool.total_unlent.amount += change; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + } + template int64_t system_contract::rent_rex( T& table, const name& from, const name& receiver, const asset& payment, const asset& fund ) { @@ -961,6 +1000,17 @@ namespace eosiosystem { return rex_received; } + void system_contract::add_to_rex_return_pool( const asset& fee ) + { + update_rex_pool(); + const uint32_t cts = current_time_point().sec_since_epoch(); + time_point_sec effective_time{ cts - cts % seconds_per_day }; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + return_pool.return_buckets[effective_time] += fee.amount; + return_pool.current_rate_of_increase += fee.amount; + }); + } + /** * @brief Updates owner REX balance upon buying REX tokens * From 4507d1b6753f2fd860829c0f768eda75cbbe576d Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 15 Nov 2019 18:06:42 -0500 Subject: [PATCH 02/24] REX changes --- .../include/eosio.system/eosio.system.hpp | 1 + contracts/eosio.system/src/rex.cpp | 69 +++++++++++++++---- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 2cc9d0c92..ec349124b 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,6 +336,7 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; int64_t current_rate_of_increase = 0; + int64_t residue = 0; time_point_sec last_update_time; std::map return_buckets; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index c55c798ab..f9ba8cabe 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -452,15 +452,13 @@ namespace eosiosystem { */ void system_contract::add_loan_to_rex_pool( const asset& payment, int64_t rented_tokens, bool new_loan ) { + add_to_rex_return_pool( payment ); _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& rt ) { // add payment to total_rent rt.total_rent.amount += payment.amount; // move rented_tokens from total_unlent to total_lent rt.total_unlent.amount -= rented_tokens; rt.total_lent.amount += rented_tokens; - // add payment to total_unlent - rt.total_unlent.amount += payment.amount; - rt.total_lendable.amount = rt.total_unlent.amount + rt.total_lent.amount; // increment loan_num if a new loan is being created if ( new_loan ) { rt.loan_num++; @@ -620,18 +618,39 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const int32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); + const int32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + + if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { + return; + } + + if ( _rexretpool.begin()->residue > 0 ) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { + pool.total_unlent.amount += _rexretpool.begin()->residue; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.residue = 0; + }); + } + + if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.last_update_time = ct; + }); + return; + } const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); const auto time_threshold = ct - eosio::days(num_of_days); int64_t change = change_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { auto& return_buckets = return_pool.return_buckets; - auto iter= return_buckets.begin(); - while ( iter!= return_buckets.begin() && iter->first <= time_threshold ) { + auto iter = return_buckets.begin(); + while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); @@ -649,7 +668,7 @@ namespace eosiosystem { return; } - _rexpool.modify(_rexpool.begin(), same_payer, [&](auto& pool) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); @@ -1003,11 +1022,33 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - const uint32_t cts = current_time_point().sec_since_epoch(); - time_point_sec effective_time{ cts - cts % seconds_per_day }; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&](auto& return_pool) { - return_pool.return_buckets[effective_time] += fee.amount; - return_pool.current_rate_of_increase += fee.amount; + const uint32_t num_of_days = 30; + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + + if ( _rexretpool.begin() == _rexretpool.end() ) { + _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { + return_pool.last_update_time = ct; + }); + } + + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + time_point_sec effective_time{ cts - cts % seconds_per_day }; + auto& return_buckets = return_pool.return_buckets; + auto& current_rate_of_increase = return_pool.current_rate_of_increase; + auto iter = return_buckets.find( effective_time ); + if ( iter != return_buckets.end() ) { + iter->second += fee.amount; + } else { + int64_t residue = 0; + if ( !return_buckets.empty() ) { + uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / ( num_of_days * seconds_per_day ); + } + return_pool.residue += residue; + current_rate_of_increase += return_buckets.rbegin()->second; + return_buckets[effective_time] = fee.amount; + } }); } From 44f5884824786fcd183199877ebc8e444c0c3068 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 19 Nov 2019 10:23:31 -0500 Subject: [PATCH 03/24] Changes to REX return buckets --- .../include/eosio.system/eosio.system.hpp | 2 ++ contracts/eosio.system/src/rex.cpp | 27 ++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index ec349124b..b8f991734 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -59,6 +59,7 @@ namespace eosiosystem { static constexpr uint32_t seconds_per_year = 52 * 7 * 24 * 3600; static constexpr uint32_t seconds_per_day = 24 * 3600; + static constexpr uint32_t seconds_per_hour = 3600; static constexpr int64_t useconds_per_year = int64_t(seconds_per_year) * 1000'000ll; static constexpr int64_t useconds_per_day = int64_t(seconds_per_day) * 1000'000ll; static constexpr uint32_t blocks_per_day = 2 * seconds_per_day; // half seconds per day @@ -335,6 +336,7 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; + uint8_t hours_per_bucket = 12; int64_t current_rate_of_increase = 0; int64_t residue = 0; time_point_sec last_update_time; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index f9ba8cabe..58937b59a 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,8 +618,8 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const int32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); + constexpr int32_t total_duration = 30 * seconds_per_day; + const time_point_sec ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; @@ -641,10 +641,10 @@ namespace eosiosystem { }); return; } - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / ( num_of_days * seconds_per_day ); - const auto time_threshold = ct - eosio::days(num_of_days); + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - total_duration }; int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { @@ -655,7 +655,7 @@ namespace eosiosystem { ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); const int64_t rate = iter->second; - int64_t surplus = ( uint128_t(overtime) * rate ) / ( num_of_days * seconds_per_day ); + const int64_t surplus = ( uint128_t(overtime) * rate ) / total_duration; change -= surplus; return_pool.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -1022,9 +1022,9 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - const uint32_t num_of_days = 30; - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + constexpr uint32_t total_duration = 30 * seconds_per_day; + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { @@ -1032,8 +1032,11 @@ namespace eosiosystem { }); } + const uint8_t hours_per_bucket = _rexretpool.begin()->hours_per_bucket; + const uint32_t bucket_interval = hours_per_bucket * seconds_per_hour; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - time_point_sec effective_time{ cts - cts % seconds_per_day }; + time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; auto& return_buckets = return_pool.return_buckets; auto& current_rate_of_increase = return_pool.current_rate_of_increase; auto iter = return_buckets.find( effective_time ); @@ -1043,7 +1046,7 @@ namespace eosiosystem { int64_t residue = 0; if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / ( num_of_days * seconds_per_day ); + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; } return_pool.residue += residue; current_rate_of_increase += return_buckets.rbegin()->second; From be375971b8850f0f436c9f5f577cfe0033048d70 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 19 Nov 2019 18:26:40 -0500 Subject: [PATCH 04/24] REX changes testing --- contracts/eosio.system/src/rex.cpp | 8 ++++---- tests/eosio.system_tester.hpp | 21 +++++++++++++++++++++ tests/eosio.system_tests.cpp | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 58937b59a..aa268529a 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -1032,8 +1032,7 @@ namespace eosiosystem { }); } - const uint8_t hours_per_bucket = _rexretpool.begin()->hours_per_bucket; - const uint32_t bucket_interval = hours_per_bucket * seconds_per_hour; + const uint32_t bucket_interval = _rexretpool.begin()->hours_per_bucket * seconds_per_hour; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; @@ -1047,9 +1046,10 @@ namespace eosiosystem { if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; + current_rate_of_increase += return_buckets.rbegin()->second; } - return_pool.residue += residue; - current_rate_of_increase += return_buckets.rbegin()->second; + return_pool.residue += residue; + // current_rate_of_increase += return_buckets.rbegin()->second; return_buckets[effective_time] = fee.amount; } }); diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index 179d4b0fa..acf3b6c60 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -638,6 +638,27 @@ class eosio_system_tester : public TESTER { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_pool", data, abi_serializer_max_time ); } + fc::variant get_rex_return_pool() const { + vector data; + const auto& db = control->db(); + namespace chain = eosio::chain; + const auto* t_id = db.find( boost::make_tuple( config::system_account_name, config::system_account_name, N(rexretpool) ) ); + if ( !t_id ) { + return fc::variant(); + } + + const auto& idx = db.get_index(); + + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, 0 ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || 0 != itr->primary_key ) { + return fc::variant(); + } + + data.resize( itr->value.size() ); + memcpy( data.data(), itr->value.data(), data.size() ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_pool", data, abi_serializer_max_time ); + } + void setup_rex_accounts( const std::vector& accounts, const asset& init_balance, const asset& net = core_sym::from_string("80.0000"), diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 1eed42e40..71239404f 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3613,6 +3613,7 @@ BOOST_FIXTURE_TEST_CASE( rex_auth, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE( buy_sell_rex, eosio_system_tester ) try { const int64_t ratio = 10000; @@ -3850,13 +3851,15 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( ratio * init_tot_lendable.get_amount(), rex_pool["total_rex"].as().get_amount() ); BOOST_REQUIRE_EQUAL( rex_pool["total_rex"].as(), get_rex_balance(alice) ); + BOOST_REQUIRE( get_rex_return_pool().is_null() ); + { // bob rents cpu for carol const asset fee = core_sym::from_string("17.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, carol, fee ) ); BOOST_REQUIRE_EQUAL( init_balance - fee, get_rex_fund(bob) ); rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( init_tot_lendable + fee, rex_pool["total_lendable"].as() ); // 65 + 17 + BOOST_REQUIRE_EQUAL( init_tot_lendable, rex_pool["total_lendable"].as() ); // 65 BOOST_REQUIRE_EQUAL( init_tot_rent + fee, rex_pool["total_rent"].as() ); // 100 + 17 int64_t expected_total_lent = bancor_convert( init_tot_rent.get_amount(), init_tot_unlent.get_amount(), fee.get_amount() ); BOOST_REQUIRE_EQUAL( expected_total_lent, @@ -3864,6 +3867,12 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( rex_pool["total_lent"].as() + rex_pool["total_unlent"].as(), rex_pool["total_lendable"].as() ); + auto rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE( !rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + + // test that carol's resource limits have been updated properly BOOST_REQUIRE_EQUAL( expected_total_lent, get_cpu_limit( carol ) - init_cpu_limit ); BOOST_REQUIRE_EQUAL( 0, get_net_limit( carol ) - init_net_limit ); @@ -3878,6 +3887,12 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { produce_block( fc::days(20) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); BOOST_REQUIRE_EQUAL( success(), cancelrexorder( alice ) ); + + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE( !rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); From d6de1a53e2e4132a84c526871d578aa53c1d9259 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Thu, 21 Nov 2019 09:51:50 -0500 Subject: [PATCH 05/24] REX changes testing - 2 --- .../include/eosio.system/eosio.system.hpp | 4 +- contracts/eosio.system/src/rex.cpp | 46 +++++++++++-------- tests/eosio.system_tests.cpp | 11 +++-- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index b8f991734..df19f8233 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,12 +336,14 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; - uint8_t hours_per_bucket = 12; int64_t current_rate_of_increase = 0; int64_t residue = 0; time_point_sec last_update_time; std::map return_buckets; + static constexpr uint32_t total_duration = 30 * seconds_per_day; + static constexpr uint8_t hours_per_bucket = 12; + uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index aa268529a..7d4951a1b 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,8 +618,7 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - constexpr int32_t total_duration = 30 * seconds_per_day; - const time_point_sec ct = current_time_point(); + const time_point_sec ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; @@ -634,17 +633,24 @@ namespace eosiosystem { return_pool.residue = 0; }); } - + /* if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { return_pool.last_update_time = ct; }); return; } - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + */ + if ( _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { + return_pool.current_rate_of_increase += return_pool.return_buckets.rbegin()->second; + }); + } + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / total_duration; - const time_point_sec time_threshold{ ct.sec_since_epoch() - total_duration }; + const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { @@ -655,7 +661,7 @@ namespace eosiosystem { ++next; const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate ) / total_duration; + const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; change -= surplus; return_pool.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -1022,35 +1028,39 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - constexpr uint32_t total_duration = 30 * seconds_per_day; - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; + const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { - return_pool.last_update_time = ct; + return_pool.last_update_time = effective_time; }); } - const uint32_t bucket_interval = _rexretpool.begin()->hours_per_bucket * seconds_per_hour; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; auto& return_buckets = return_pool.return_buckets; auto& current_rate_of_increase = return_pool.current_rate_of_increase; auto iter = return_buckets.find( effective_time ); if ( iter != return_buckets.end() ) { iter->second += fee.amount; } else { + // create a new bucket + // but first process the previous bucket if it exists int64_t residue = 0; if ( !return_buckets.empty() ) { uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / total_duration; - current_rate_of_increase += return_buckets.rbegin()->second; + if ( interval < rex_return_pool::total_duration ) { + residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / rex_return_pool::total_duration; + current_rate_of_increase += return_buckets.rbegin()->second; + } else { + residue = return_buckets.rbegin()->second; + // erase rbegin + } } return_pool.residue += residue; - // current_rate_of_increase += return_buckets.rbegin()->second; - return_buckets[effective_time] = fee.amount; + return_buckets.emplace( effective_time, fee.amount ); } }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 71239404f..d1ee12ff4 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3890,14 +3890,17 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); - BOOST_REQUIRE_EQUAL( init_balance + fee, get_rex_fund(alice) ); + auto expected_rex_fund = (init_balance + fee).get_amount(); + auto actual_rex_fund = get_rex_fund(alice).get_amount(); + BOOST_REQUIRE_EQUAL( true, within_one( expected_rex_fund, actual_rex_fund ) ); + BOOST_REQUIRE( actual_rex_fund <= expected_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -3955,7 +3958,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_sell_rex, eosio_system_tester ) try { const asset fee = core_sym::from_string("7.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, carol, fee ) ); rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( init_tot_lendable + fee, rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( init_tot_lendable, rex_pool["total_lendable"].as() ); BOOST_REQUIRE_EQUAL( init_tot_rent + fee, rex_pool["total_rent"].as() ); produce_block( fc::days(5) ); From 43861c68151b0c71ba19a07274f495f0b37bee53 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 27 Nov 2019 23:27:34 -0700 Subject: [PATCH 06/24] REX changes - fix unit tests --- .../include/eosio.system/eosio.system.hpp | 3 +- contracts/eosio.system/src/rex.cpp | 79 ++++++------------- tests/eosio.system_tests.cpp | 70 ++++++++++------ 3 files changed, 69 insertions(+), 83 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index df19f8233..902fb62a3 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -336,9 +336,8 @@ namespace eosiosystem { struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; - int64_t current_rate_of_increase = 0; - int64_t residue = 0; time_point_sec last_update_time; + int64_t current_rate_of_increase = 0; std::map return_buckets; static constexpr uint32_t total_duration = 30 * seconds_per_day; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 7d4951a1b..86b33c619 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -624,50 +624,40 @@ namespace eosiosystem { return; } - if ( _rexretpool.begin()->residue > 0 ) { - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { - pool.total_unlent.amount += _rexretpool.begin()->residue; - pool.total_lendable = pool.total_unlent + pool.total_lent; - }); - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.residue = 0; - }); - } - /* - if ( _rexretpool.begin()->return_buckets.empty() || ct <= _rexretpool.begin()->return_buckets.begin()->first ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.last_update_time = ct; - }); - return; - } - */ - if ( _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - return_pool.current_rate_of_increase += return_pool.return_buckets.rbegin()->second; + const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() + && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first + && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; + int64_t new_bucket_overestimate = 0; + if ( new_return_bucket ) { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; + const uint32_t dt = rp.return_buckets.rbegin()->first.sec_since_epoch() - rp.last_update_time.sec_since_epoch(); + new_bucket_overestimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const int32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration + - new_bucket_overestimate; const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; int64_t change = change_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - auto& return_buckets = return_pool.return_buckets; + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = time_threshold.sec_since_epoch() - iter->first.sec_since_epoch(); + const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); const int64_t rate = iter->second; const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; - change -= surplus; - return_pool.current_rate_of_increase -= rate; + change -= surplus; + rp.current_rate_of_increase -= rate; return_buckets.erase(iter); iter = next; } - return_pool.last_update_time = ct; + rp.last_update_time = ct; }); if ( change <= 0 ) { @@ -1029,39 +1019,18 @@ namespace eosiosystem { { update_rex_pool(); - const time_point_sec ct = current_time_point(); - const uint32_t cts = ct.sec_since_epoch(); + const uint32_t cts = current_time_point().sec_since_epoch(); const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; + if ( _rexretpool.begin() == _rexretpool.end() ) { - _rexretpool.emplace( get_self(), [&]( auto& return_pool ) { - return_pool.last_update_time = effective_time; + _rexretpool.emplace( get_self(), [&]( auto& rp ) { + rp.last_update_time = effective_time; }); } - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& return_pool ) { - auto& return_buckets = return_pool.return_buckets; - auto& current_rate_of_increase = return_pool.current_rate_of_increase; - auto iter = return_buckets.find( effective_time ); - if ( iter != return_buckets.end() ) { - iter->second += fee.amount; - } else { - // create a new bucket - // but first process the previous bucket if it exists - int64_t residue = 0; - if ( !return_buckets.empty() ) { - uint32_t interval = cts - return_buckets.rbegin()->first.sec_since_epoch(); - if ( interval < rex_return_pool::total_duration ) { - residue = ( uint128_t(return_buckets.rbegin()->second) * interval ) / rex_return_pool::total_duration; - current_rate_of_increase += return_buckets.rbegin()->second; - } else { - residue = return_buckets.rbegin()->second; - // erase rbegin - } - } - return_pool.residue += residue; - return_buckets.emplace( effective_time, fee.amount ); - } + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.return_buckets[effective_time] += fee.amount; }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index d1ee12ff4..399c3d169 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3869,9 +3869,7 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); // test that carol's resource limits have been updated properly BOOST_REQUIRE_EQUAL( expected_total_lent, get_cpu_limit( carol ) - init_cpu_limit ); @@ -3890,7 +3888,6 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["residue"].as() ); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); @@ -4018,30 +4015,31 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("20000.0000") ) ); } - const asset rent_payment = core_sym::from_string("40000.0000"); + produce_block( fc::days(25) ); + const asset rent_payment = core_sym::from_string("40000.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( frank, frank, rent_payment, rent_payment ) ); + produce_block( fc::days(4) ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); + const auto init_rex_pool = get_rex_pool(); const int64_t total_lendable = init_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = init_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_alice_rex.get_amount()) * total_lendable ) / total_rex; - produce_block( fc::days(5) ); - BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol(SY(4,REX)) ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); - produce_block( fc::days(5) ); - init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( carol, get_rex_balance(carol) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); - + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_balance(bob) ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_balance(carol) ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_balance(alice) ); @@ -4058,7 +4056,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); // wait for 30 days minus 1 hour - produce_block( fc::hours(19*24 + 23) ); + produce_block( fc::hours(23) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); BOOST_REQUIRE_EQUAL( true, get_rex_order(bob)["is_open"].as() ); @@ -4081,21 +4079,28 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { } { + BOOST_REQUIRE_EQUAL( false, get_rex_order(bob)["is_open"].as() ); + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_order(bob)["rex_requested"].as() ); + BOOST_TEST_REQUIRE ( 0 < get_rex_order(bob)["proceeds"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_order(alice)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(alice)["proceeds"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( false, get_rex_order(bob)["is_open"].as() ); - BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_order(bob)["rex_requested"].as() ); - BOOST_REQUIRE ( 0 < get_rex_order(bob)["proceeds"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( true, get_rex_order(carol)["is_open"].as() ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_order(carol)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("rex loans are currently not available"), rentcpu( frank, frank, core_sym::from_string("1.0000") ) ); } + produce_blocks(2); + produce_block( fc::hours(13) ); + produce_blocks(2); + produce_block( fc::days(30) ); + produce_blocks(2); + { auto trace1 = base_tester::push_action( config::system_account_name, N(updaterex), bob, mvo()("owner", bob) ); auto trace2 = base_tester::push_action( config::system_account_name, N(updaterex), carol, mvo()("owner", carol) ); @@ -4223,7 +4228,8 @@ BOOST_FIXTURE_TEST_CASE( rex_loans, eosio_system_tester ) try { } // wait for 30 days, frank's loan will be renewed at the current price - produce_block( fc::hours(30*24 + 1) ); + produce_block( fc::minutes(30*24*60 - 1) ); + BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); rex_pool = get_rex_pool(); { int64_t unlent_tokens = bancor_convert( rex_pool["total_unlent"].as().get_amount(), @@ -4235,6 +4241,8 @@ BOOST_FIXTURE_TEST_CASE( rex_loans, eosio_system_tester ) try { payment.get_amount() ); } + produce_block( fc::minutes(2) ); + BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset::from_string("1.0000 REX") ) ); loan_info = get_cpu_loan(1); @@ -4723,15 +4731,17 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const int64_t init_stake = get_voter_info( alice )["staked"].as(); + // alice buys rex const asset payment = core_sym::from_string("25000.0000"); BOOST_REQUIRE_EQUAL( success(), buyrex( alice, payment ) ); BOOST_REQUIRE_EQUAL( payment, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake ); + // emily rents cpu const asset fee = core_sym::from_string("50.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, fee ) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - BOOST_REQUIRE_EQUAL( payment + fee, get_rex_vote_stake(alice) ); + BOOST_REQUIRE_EQUAL( payment, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info( alice )["staked"].as() - init_stake ); // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers @@ -4751,9 +4761,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 20) ) ); + vote( alice, { producer_names.begin(), producer_names.begin() + 20 } ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4761,23 +4771,25 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - produce_block( fc::days(20) ); + produce_block( fc::days(10) ); BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); + BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); + produce_block( fc::hours(19 * 24 + 23) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); const int64_t total_lendable = current_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = current_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_rex.get_amount()) * total_lendable ) / total_rex; - produce_block( fc::days(5) ); const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_REQUIRE_EQUAL( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ); + BOOST_TEST_REQUIRE( within_one( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ) ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4827,18 +4839,20 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_REQUIRE_EQUAL( purchase, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( purchase.get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); const auto init_rex_pool = get_rex_pool(); const asset rent = core_sym::from_string("25.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + + produce_block( fc::days(31) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const auto curr_rex_pool = get_rex_pool(); BOOST_REQUIRE_EQUAL( curr_rex_pool["total_lendable"].as(), init_rex_pool["total_lendable"].as() + rent ); - BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); + + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); BOOST_REQUIRE_EQUAL( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == @@ -4850,11 +4864,15 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes const asset to_cpu_stake = core_sym::from_string("40.0000"); transfer( config::system_account_name, alice, to_net_stake + to_cpu_stake, config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + produce_block( fc::hours(30 * 24 + 12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); + produce_block( fc::hours(30 * 24 + 12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + rent) == From 6b6898c6416746dc9fc74ed25937cb9acd3370d0 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 29 Nov 2019 14:49:48 -0700 Subject: [PATCH 07/24] REX changes - distribute ramfee and namebids --- contracts/eosio.system/src/rex.cpp | 26 +++++++------- tests/eosio.system_tests.cpp | 54 +++++++++++++++++++----------- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 86b33c619..b33e597be 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -624,25 +624,25 @@ namespace eosiosystem { return; } + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; - int64_t new_bucket_overestimate = 0; + int64_t new_bucket_estimate = 0; if ( new_return_bucket ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint32_t dt = rp.return_buckets.rbegin()->first.sec_since_epoch() - rp.last_update_time.sec_since_epoch(); - new_bucket_overestimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; + const uint32_t dt = ct.sec_since_epoch() - rp.return_buckets.rbegin()->first.sec_since_epoch(); + new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration - - new_bucket_overestimate; - const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + int64_t change = change_estimate + new_bucket_estimate; - int64_t change = change_estimate; _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); @@ -651,7 +651,8 @@ namespace eosiosystem { ++next; const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate ) / rex_return_pool::total_duration; + const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) + / rex_return_pool::total_duration; change -= surplus; rp.current_rate_of_increase -= rate; return_buckets.erase(iter); @@ -872,10 +873,7 @@ namespace eosiosystem { { #if CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX if ( rex_available() ) { - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& rp ) { - rp.total_unlent.amount += amount.amount; - rp.total_lendable.amount += amount.amount; - }); + add_to_rex_return_pool( amount ); // inline transfer to rex_account token::transfer_action transfer_act{ token_account, { from, active_permission } }; transfer_act.send( from, rex_account, amount, diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 399c3d169..f220bba16 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -27,7 +27,8 @@ using namespace eosio_system; BOOST_AUTO_TEST_SUITE(eosio_system_tests) -bool within_one(int64_t a, int64_t b) { return std::abs(a - b) <= 1; } +bool within_error(int64_t a, int64_t b, int64_t err) { return std::abs(a - b) <= err; }; +bool within_one(int64_t a, int64_t b) { return within_error(a, b, 1); } BOOST_FIXTURE_TEST_CASE( buysell, eosio_system_tester ) try { @@ -3896,8 +3897,8 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); auto expected_rex_fund = (init_balance + fee).get_amount(); auto actual_rex_fund = get_rex_fund(alice).get_amount(); - BOOST_REQUIRE_EQUAL( true, within_one( expected_rex_fund, actual_rex_fund ) ); - BOOST_REQUIRE( actual_rex_fund <= expected_rex_fund ); + BOOST_REQUIRE_EQUAL( true, within_error( expected_rex_fund, actual_rex_fund, 2 ) ); + BOOST_TEST_REQUIRE( actual_rex_fund <= expected_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -4327,12 +4328,20 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( get_balance( N(eosio.rex) ), cur_rex_balance + core_sym::from_string("0.3500") ); cur_rex_balance = get_balance( N(eosio.rex) ); + + produce_blocks( 1 ); + produce_block( fc::hours(30*24 + 12) ); + produce_blocks( 1 ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); auto cur_rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( cur_rex_balance, cur_rex_pool["total_unlent"].as() ); - BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["total_lent"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, cur_rex_pool["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["namebid_proceeds"].as().get_amount() ); + BOOST_TEST_REQUIRE( within_one( cur_rex_balance.get_amount(), cur_rex_pool["total_unlent"].as().get_amount() ) ); + BOOST_TEST_REQUIRE( cur_rex_balance >= cur_rex_pool["total_unlent"].as() ); + BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["total_lent"].as().get_amount() ); + BOOST_TEST_REQUIRE( within_one( cur_rex_balance.get_amount(), cur_rex_pool["total_lendable"].as().get_amount() ) ); + BOOST_TEST_REQUIRE( cur_rex_balance >= cur_rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( 0, cur_rex_pool["namebid_proceeds"].as().get_amount() ); // required for closing namebids cross_15_percent_threshold(); @@ -4354,8 +4363,14 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_balance( N(eosio.names) ).get_amount() ); cur_rex_balance = get_balance( N(eosio.rex) ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_unlent"].as() ); + produce_block( fc::hours(30*24 + 13) ); + produce_blocks( 1 ); + + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); + + BOOST_TEST_REQUIRE( within_error( cur_rex_balance.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 4 ) ); + BOOST_TEST_REQUIRE( cur_rex_balance.get_amount() >= get_rex_pool()["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), get_rex_pool()["total_unlent"].as() ); } FC_LOG_AND_RETHROW() @@ -4789,7 +4804,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_TEST_REQUIRE( within_one( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount() ) ); + BOOST_TEST_REQUIRE( within_error( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount(), 2 ) ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4804,7 +4819,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_test::tolerance(1e-10) ) try { +BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_test::tolerance(1e-8) ) try { cross_15_percent_threshold(); @@ -4850,11 +4865,12 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const auto curr_rex_pool = get_rex_pool(); - BOOST_REQUIRE_EQUAL( curr_rex_pool["total_lendable"].as(), init_rex_pool["total_lendable"].as() + rent ); + BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), + init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); - BOOST_REQUIRE_EQUAL( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); - BOOST_REQUIRE_EQUAL( purchase + rent, get_rex_vote_stake(alice) ); + BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); + BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == @@ -4864,18 +4880,18 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes const asset to_cpu_stake = core_sym::from_string("40.0000"); transfer( config::system_account_name, alice, to_net_stake + to_cpu_stake, config::system_account_name ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); - produce_block( fc::hours(30 * 24 + 12) ); + produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); + BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 2 ) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); - produce_block( fc::hours(30 * 24 + 12) ); + produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); - BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + rent) == + BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 3 ) ); + BOOST_TEST_REQUIRE ( stake2votes(init_stake + get_rex_vote_stake(alice) ) == get_producer_info(producer_names[0])["total_votes"].as_double() ); } FC_LOG_AND_RETHROW() From 048753ca81b6546075feaea0156f3a4aa4c555b2 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Sun, 1 Dec 2019 23:28:36 -0500 Subject: [PATCH 08/24] REX changes - more testing --- tests/eosio.system_tests.cpp | 105 +++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index f220bba16..31f9a9b6b 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5157,6 +5157,111 @@ BOOST_FIXTURE_TEST_CASE( b1_vesting, eosio_system_tester ) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { + + BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); + + const asset init_balance = core_sym::from_string("100000.0000"); + const std::vector accounts = { N(aliceaccount), N(bobbyaccount) }; + account_name alice = accounts[0], bob = accounts[1]; + setup_rex_accounts( accounts, init_balance ); + + const asset payment = core_sym::from_string("100000.0000"); + { + BOOST_REQUIRE_EQUAL( success(), buyrex( alice, payment ) ); + auto rex_pool = get_rex_pool(); + BOOST_REQUIRE_EQUAL( payment, rex_pool["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( payment, rex_pool["total_unlent"].as() ); + + BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); + } + + { + const asset fee = core_sym::from_string("30.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + auto rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + + produce_block( fc::hours(12) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + + uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t expected = payment.get_amount() + change; + + auto rex_pool = get_rex_pool(); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); + + produce_blocks( 1 ); + produce_block( fc::days(25) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t2 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600); + expected = payment.get_amount() + change; + + rex_pool = get_rex_pool(); + BOOST_TEST_REQUIRE( within_one( expected, rex_pool["total_lendable"].as().get_amount() ) ); + + produce_blocks( 1 ); + produce_block( fc::days(5) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + + rex_pool = get_rex_pool(); + expected = payment.get_amount() + fee.get_amount(); + BOOST_TEST_REQUIRE( within_error( expected, rex_pool["total_lendable"].as().get_amount(), 2 ) ); + BOOST_TEST_REQUIRE( expected >= rex_pool["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( rex_pool["total_lendable"].as(), + rex_pool["total_unlent"].as() ); + } + + produce_block( fc::hours(1) ); + + { + const asset init_lendable = get_rex_pool()["total_lendable"].as(); + const asset fee = core_sym::from_string("15.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + auto rex_return_pool = get_rex_return_pool(); + uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + produce_block( fc::hours(1) ); + BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( t0 + 3600, t1 ); + + produce_block( fc::hours(12) ); + BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + produce_block( fc::hours(8) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + + produce_block( fc::days(30) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_TEST_REQUIRE( (init_lendable + fee + fee).get_amount() < get_rex_pool()["total_lendable"].as().get_amount() ); + + produce_block( fc::days(1) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), + get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); + } + +} FC_LOG_AND_RETHROW() + + BOOST_AUTO_TEST_CASE( setabi_bios ) try { validating_tester t( validating_tester::default_config() ); t.execute_setup_policy( setup_policy::preactivate_feature_only ); From 2c91b6dab188c1b93ac0adfc573223b4259d88a3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 01:06:15 -0500 Subject: [PATCH 09/24] REX changes - unlent lower bound --- contracts/eosio.system/src/rex.cpp | 2 +- tests/eosio.system_tests.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index b33e597be..774f88162 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -733,7 +733,7 @@ namespace eosiosystem { asset stake_change( 0, core_symbol() ); bool success = false; - const int64_t unlent_lower_bound = ( uint128_t(2) * rexitr->total_lent.amount ) / 10; + const int64_t unlent_lower_bound = rexitr->total_lent.amount / 10; const int64_t available_unlent = rexitr->total_unlent.amount - unlent_lower_bound; // available_unlent <= 0 is possible if ( proceeds.amount <= available_unlent ) { const int64_t init_vote_stake_amount = bitr->vote_stake.amount; diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 31f9a9b6b..4e7219d75 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3993,8 +3993,8 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { setup_rex_accounts( accounts, init_balance ); const auto purchase1 = core_sym::from_string("50000.0000"); - const auto purchase2 = core_sym::from_string("235500.0000"); - const auto purchase3 = core_sym::from_string("234500.0000"); + const auto purchase2 = core_sym::from_string("105500.0000"); + const auto purchase3 = core_sym::from_string("104500.0000"); const auto init_stake = get_voter_info(alice)["staked"].as(); BOOST_REQUIRE_EQUAL( success(), buyrex( alice, purchase1) ); BOOST_REQUIRE_EQUAL( success(), buyrex( bob, purchase2) ); @@ -4013,12 +4013,12 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( core_sym::from_string("20000.0000"), get_rex_pool()["total_rent"].as() ); for (uint8_t i = 0; i < 4; ++i) { - BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("20000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, emily, core_sym::from_string("12000.0000") ) ); } produce_block( fc::days(25) ); - const asset rent_payment = core_sym::from_string("40000.0000"); + const asset rent_payment = core_sym::from_string("46000.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( frank, frank, rent_payment, rent_payment ) ); produce_block( fc::days(4) ); @@ -4675,7 +4675,7 @@ BOOST_FIXTURE_TEST_CASE( rex_savings, eosio_system_tester ) try { produce_block( fc::days(5) ); - BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, core_sym::from_string("2000.0000") ) ); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, core_sym::from_string("3000.0000") ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 9 * rex_bucket_amount / 10, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( rex_bucket, get_rex_balance( alice ) ); BOOST_REQUIRE_EQUAL( success(), mvtosavings( alice, asset( rex_bucket_amount / 10, rex_sym ) ) ); @@ -4948,11 +4948,11 @@ BOOST_FIXTURE_TEST_CASE( rex_lower_bound, eosio_system_tester ) try { const int64_t tot_lent = rex_pool["total_lent"].as().get_amount(); const int64_t tot_lendable = rex_pool["total_lendable"].as().get_amount(); double rex_per_eos = double(tot_rex) / double(tot_lendable); - int64_t sell_amount = rex_per_eos * ( tot_unlent - 0.19 * tot_lent ); + int64_t sell_amount = rex_per_eos * ( tot_unlent - 0.09 * tot_lent ); produce_block( fc::days(5) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( sell_amount, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( success(), cancelrexorder( alice ) ); - sell_amount = rex_per_eos * ( tot_unlent - 0.2 * tot_lent ); + sell_amount = rex_per_eos * ( tot_unlent - 0.1 * tot_lent ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( sell_amount, rex_sym ) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("no sellrex order is scheduled"), cancelrexorder( alice ) ); From 07584f7ace34cfc92ed99ce31570c6c08b1957f3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 17:32:23 -0500 Subject: [PATCH 10/24] REX changes - use microseconds instead of seconds --- .../include/eosio.system/eosio.system.hpp | 13 ++++---- contracts/eosio.system/src/rex.cpp | 20 ++++++------ tests/eosio.system_tests.cpp | 31 ++++++++++--------- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 902fb62a3..be473fcfc 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -62,6 +62,7 @@ namespace eosiosystem { static constexpr uint32_t seconds_per_hour = 3600; static constexpr int64_t useconds_per_year = int64_t(seconds_per_year) * 1000'000ll; static constexpr int64_t useconds_per_day = int64_t(seconds_per_day) * 1000'000ll; + static constexpr int64_t useconds_per_hour = int64_t(seconds_per_hour) * 1000'000ll; static constexpr uint32_t blocks_per_day = 2 * seconds_per_day; // half seconds per day static constexpr int64_t min_activated_stake = 150'000'000'0000; @@ -335,13 +336,13 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { - uint8_t version = 0; - time_point_sec last_update_time; - int64_t current_rate_of_increase = 0; - std::map return_buckets; + uint8_t version = 0; + time_point last_update_time; + int64_t current_rate_of_increase = 0; + std::map return_buckets; - static constexpr uint32_t total_duration = 30 * seconds_per_day; - static constexpr uint8_t hours_per_bucket = 12; + static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 774f88162..5bf02df16 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -618,16 +618,16 @@ namespace eosiosystem { void system_contract::update_rex_pool() { - const time_point_sec ct = current_time_point(); + const time_point ct = current_time_point(); if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { return; } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint32_t time_interval = ct.sec_since_epoch() - _rexretpool.begin()->last_update_time.sec_since_epoch(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; - const time_point_sec time_threshold{ ct.sec_since_epoch() - rex_return_pool::total_duration }; + const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; + const uint64_t time_interval = ct.time_since_epoch().count() - _rexretpool.begin()->last_update_time.time_since_epoch().count(); + const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; + const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first @@ -636,7 +636,7 @@ namespace eosiosystem { if ( new_return_bucket ) { _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint32_t dt = ct.sec_since_epoch() - rp.return_buckets.rbegin()->first.sec_since_epoch(); + const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; }); } @@ -649,7 +649,7 @@ namespace eosiosystem { while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = ct.sec_since_epoch() - ( iter->first.sec_since_epoch() + rex_return_pool::total_duration ); + const uint64_t overtime = ct.time_since_epoch().count() - ( iter->first.time_since_epoch().count() + rex_return_pool::total_duration ); const int64_t rate = iter->second; const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) / rex_return_pool::total_duration; @@ -1017,9 +1017,9 @@ namespace eosiosystem { { update_rex_pool(); - const uint32_t cts = current_time_point().sec_since_epoch(); - const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; - const time_point_sec effective_time{ cts - cts % bucket_interval + bucket_interval }; + const int64_t cts = current_time_point().time_since_epoch().count(); + const int64_t bucket_interval = rex_return_pool::hours_per_bucket * useconds_per_hour; + const time_point effective_time{ eosio::microseconds{cts - cts % bucket_interval + bucket_interval} }; if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 4e7219d75..c3a79dc71 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4024,23 +4024,24 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { produce_block( fc::days(4) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); - + const auto init_rex_pool = get_rex_pool(); const int64_t total_lendable = init_rex_pool["total_lendable"].as().get_amount(); const int64_t total_rex = init_rex_pool["total_rex"].as().get_amount(); const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_alice_rex.get_amount()) * total_lendable ) / total_rex; - BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol(SY(4,REX)) ) ) ); + BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol{SY(4,REX)} ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); - BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); - BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); + // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); + // BOOST_REQUIRE_EQUAL( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ); + // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( carol, get_rex_balance(carol) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance(alice) ) ); - + BOOST_REQUIRE_EQUAL( init_bob_rex, get_rex_balance(bob) ); BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_balance(carol) ); BOOST_REQUIRE_EQUAL( init_alice_rex, get_rex_balance(alice) ); @@ -4056,7 +4057,7 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( init_carol_rex, get_rex_order(carol)["rex_requested"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_order(carol)["proceeds"].as().get_amount() ); - // wait for 30 days minus 1 hour + // wait for a total of 30 days minus 1 hour produce_block( fc::hours(23) ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); BOOST_REQUIRE_EQUAL( true, get_rex_order(alice)["is_open"].as() ); @@ -5182,15 +5183,15 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - produce_block( fc::hours(12) ); + produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); int64_t expected = payment.get_amount() + change; auto rex_pool = get_rex_pool(); @@ -5201,8 +5202,8 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t2 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600); + int64_t t2 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); expected = payment.get_amount() + change; rex_pool = get_rex_pool(); @@ -5230,13 +5231,13 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { const asset fee = core_sym::from_string("15.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); - uint32_t t0 = rex_return_pool["last_update_time"].as().sec_since_epoch(); + int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); produce_block( fc::hours(1) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - uint32_t t1 = rex_return_pool["last_update_time"].as().sec_since_epoch(); - BOOST_REQUIRE_EQUAL( t0 + 3600, t1 ); + int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); From e7b7b0c7ea8c581eb5494347fd16e584a4dcfbfa Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 2 Dec 2019 18:12:17 -0500 Subject: [PATCH 11/24] REX changes - comments --- .../eosio.system/include/eosio.system/eosio.system.hpp | 7 ++++++- contracts/eosio.system/src/rex.cpp | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index be473fcfc..61d18ee8b 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -335,13 +335,18 @@ namespace eosiosystem { typedef eosio::multi_index< "rexpool"_n, rex_pool > rex_pool_table; + // `rex_return_pool` structure underlying the rex return pool table. A rex return pool table entry is defined by: + // - `version` defaulted to zero, + // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, + // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, + // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point last_update_time; int64_t current_rate_of_increase = 0; std::map return_buckets; - static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr int64_t total_duration = 30 * useconds_per_day; static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 5bf02df16..4aeef7d5e 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -616,6 +616,9 @@ namespace eosiosystem { } + /** + * @brief Adds returns from the REX return pool to the REX pool + */ void system_contract::update_rex_pool() { const time_point ct = current_time_point(); @@ -1013,6 +1016,11 @@ namespace eosiosystem { return rex_received; } + /** + * @brief Adds an amount of core tokens to the REX return pool + * + * @param fee - amount to be added + */ void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); From 854a6239bcf8c8d1a0880ed7faf2c28d6c0448d3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 9 Dec 2019 16:16:12 -0500 Subject: [PATCH 12/24] REX changes - time interval between REX pool updates --- .../include/eosio.system/eosio.system.hpp | 6 ++++ contracts/eosio.system/src/rex.cpp | 11 ++++++- tests/eosio.system_tests.cpp | 32 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 61d18ee8b..95108dc9c 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -339,14 +339,20 @@ namespace eosiosystem { // - `version` defaulted to zero, // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, + // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, + // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; + time_point last_update_time; int64_t current_rate_of_increase = 0; + int64_t cummulative_proceeds = 0; + int64_t proceeds = 0; std::map return_buckets; static constexpr int64_t total_duration = 30 * useconds_per_day; + static constexpr int64_t dist_interval = 10 * 60 * 1000'000; static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 4aeef7d5e..d47017f40 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -623,7 +623,8 @@ namespace eosiosystem { { const time_point ct = current_time_point(); - if ( _rexretpool.begin() == _rexretpool.end() || ct <= _rexretpool.begin()->last_update_time ) { + if ( _rexretpool.begin() == _rexretpool.end() || + ct < _rexretpool.begin()->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { return; } @@ -672,6 +673,9 @@ namespace eosiosystem { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.cummulative_proceeds += change; + }); } template @@ -1032,6 +1036,11 @@ namespace eosiosystem { if ( _rexretpool.begin() == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { rp.last_update_time = effective_time; + rp.proceeds += fee.amount; + }); + } else { + _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + rp.proceeds += fee.amount; }); } diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index c3a79dc71..63e0f5f91 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5183,6 +5183,7 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); produce_block( fc::hours(13) ); @@ -5215,6 +5216,7 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); rex_pool = get_rex_pool(); expected = payment.get_amount() + fee.get_amount(); @@ -5236,11 +5238,15 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); + rex_return_pool = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( 2, rex_return_pool["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::hours(8) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); @@ -5256,10 +5262,36 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); } + { + const asset fee = core_sym::from_string("25.0000"); + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + produce_block( fc::hours(13) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_0 = get_rex_pool(); + auto rex_return_pool_0 = get_rex_return_pool(); + produce_block( fc::minutes(9) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_1 = get_rex_pool(); + auto rex_return_pool_1 = get_rex_return_pool(); + BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_update_time"].as().time_since_epoch().count(), + rex_return_pool_1["last_update_time"].as().time_since_epoch().count()); + BOOST_REQUIRE_EQUAL( rex_pool_0["total_lendable"].as(), + rex_pool_1["total_lendable"].as()); + produce_block( fc::minutes(1) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + auto rex_pool_2 = get_rex_pool(); + auto rex_return_pool_2 = get_rex_return_pool(); + BOOST_TEST_REQUIRE( rex_return_pool_1["last_update_time"].as().time_since_epoch().count() < + rex_return_pool_2["last_update_time"].as().time_since_epoch().count()); + BOOST_TEST_REQUIRE( rex_pool_1["total_lendable"].as().get_amount() < + rex_pool_2["total_lendable"].as().get_amount()); + } + } FC_LOG_AND_RETHROW() From 4ef78d7201a80298c31a1fc23e9dba34c43036ec Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Mon, 9 Dec 2019 17:06:53 -0500 Subject: [PATCH 13/24] REX changes - larryk85's PR review --- contracts/eosio.system/src/rex.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index d47017f40..380cd8cc9 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -622,23 +622,24 @@ namespace eosiosystem { void system_contract::update_rex_pool() { const time_point ct = current_time_point(); + const auto ret_pool_elem = _rexretpool.begin(); - if ( _rexretpool.begin() == _rexretpool.end() || - ct < _rexretpool.begin()->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { + if ( ret_pool_elem == _rexretpool.end() || + ct < ret_pool_elem->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { return; } - const int64_t current_rate = _rexretpool.begin()->current_rate_of_increase; - const uint64_t time_interval = ct.time_since_epoch().count() - _rexretpool.begin()->last_update_time.time_since_epoch().count(); + const int64_t current_rate = ret_pool_elem->current_rate_of_increase; + const uint64_t time_interval = ct.time_since_epoch().count() - ret_pool_elem->last_update_time.time_since_epoch().count(); const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; - const bool new_return_bucket = !_rexretpool.begin()->return_buckets.empty() - && _rexretpool.begin()->last_update_time <= _rexretpool.begin()->return_buckets.rbegin()->first - && _rexretpool.begin()->return_buckets.rbegin()->first <= ct; + const bool new_return_bucket = !ret_pool_elem->return_buckets.empty() + && ret_pool_elem->last_update_time <= ret_pool_elem->return_buckets.rbegin()->first + && ret_pool_elem->return_buckets.rbegin()->first <= ct; int64_t new_bucket_estimate = 0; if ( new_return_bucket ) { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; @@ -647,7 +648,7 @@ namespace eosiosystem { int64_t change = change_estimate + new_bucket_estimate; - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { auto& return_buckets = rp.return_buckets; auto iter = return_buckets.begin(); while ( iter != return_buckets.end() && iter->first <= time_threshold ) { @@ -673,7 +674,7 @@ namespace eosiosystem { pool.total_unlent.amount += change; pool.total_lendable = pool.total_unlent + pool.total_lent; }); - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { rp.cummulative_proceeds += change; }); } From 798a32938cc1e7011920551e8cdbaa7aa25ae371 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Tue, 10 Dec 2019 18:02:50 -0500 Subject: [PATCH 14/24] REX changes - arhag's PR review --- .../include/eosio.system/eosio.system.hpp | 67 ++++---- contracts/eosio.system/src/eosio.system.cpp | 1 + contracts/eosio.system/src/rex.cpp | 147 +++++++++++------- 3 files changed, 130 insertions(+), 85 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 95108dc9c..4b24caff1 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -341,25 +341,33 @@ namespace eosiosystem { // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, - // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective + // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { - uint8_t version = 0; - - time_point last_update_time; - int64_t current_rate_of_increase = 0; - int64_t cummulative_proceeds = 0; - int64_t proceeds = 0; - std::map return_buckets; - - static constexpr int64_t total_duration = 30 * useconds_per_day; - static constexpr int64_t dist_interval = 10 * 60 * 1000'000; - static constexpr uint8_t hours_per_bucket = 12; + uint8_t version = 0; + time_point_sec last_dist_time; + time_point_sec pending_bucket_time = time_point_sec::maximum(); + time_point_sec oldest_bucket_time = time_point_sec::min(); + int64_t pending_bucket_proceeds = 0; + int64_t current_rate_of_increase = 0; + + static constexpr int32_t total_intervals = 30 * 144; // 30 days + static constexpr int32_t dist_interval = 10 * 60; // 10 minutes + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_buckets { + uint8_t version = 0; + std::map return_buckets; + + uint64_t primary_key()const { return 0; } + }; + + typedef eosio::multi_index< "retbuckets"_n, rex_return_buckets > rex_return_buckets_table; + // `rex_fund` structure underlying the rex fund table. A rex fund table entry is defined by: // - `version` defaulted to zero, // - `owner` the owner of the rex fund, @@ -457,23 +465,24 @@ namespace eosiosystem { class [[eosio::contract("eosio.system")]] system_contract : public native { private: - voters_table _voters; - producers_table _producers; - producers_table2 _producers2; - global_state_singleton _global; - global_state2_singleton _global2; - global_state3_singleton _global3; - global_state4_singleton _global4; - eosio_global_state _gstate; - eosio_global_state2 _gstate2; - eosio_global_state3 _gstate3; - eosio_global_state4 _gstate4; - rammarket _rammarket; - rex_pool_table _rexpool; - rex_return_pool_table _rexretpool; - rex_fund_table _rexfunds; - rex_balance_table _rexbalance; - rex_order_table _rexorders; + voters_table _voters; + producers_table _producers; + producers_table2 _producers2; + global_state_singleton _global; + global_state2_singleton _global2; + global_state3_singleton _global3; + global_state4_singleton _global4; + eosio_global_state _gstate; + eosio_global_state2 _gstate2; + eosio_global_state3 _gstate3; + eosio_global_state4 _gstate4; + rammarket _rammarket; + rex_pool_table _rexpool; + rex_return_pool_table _rexretpool; + rex_return_buckets_table _rexretbuckets; + rex_fund_table _rexfunds; + rex_balance_table _rexbalance; + rex_order_table _rexorders; public: static constexpr eosio::name active_permission{"active"_n}; diff --git a/contracts/eosio.system/src/eosio.system.cpp b/contracts/eosio.system/src/eosio.system.cpp index a6af9e0d0..202210c7d 100644 --- a/contracts/eosio.system/src/eosio.system.cpp +++ b/contracts/eosio.system/src/eosio.system.cpp @@ -27,6 +27,7 @@ namespace eosiosystem { _rammarket(get_self(), get_self().value), _rexpool(get_self(), get_self().value), _rexretpool(get_self(), get_self().value), + _rexretbuckets(get_self(), get_self().value), _rexfunds(get_self(), get_self().value), _rexbalance(get_self(), get_self().value), _rexorders(get_self(), get_self().value) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 380cd8cc9..663336d2f 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -621,62 +621,92 @@ namespace eosiosystem { */ void system_contract::update_rex_pool() { - const time_point ct = current_time_point(); - const auto ret_pool_elem = _rexretpool.begin(); + auto get_elapsed_intervals = [&](const time_point_sec& t1, const time_point_sec& t0) -> uint32_t { + return (t1.sec_since_epoch() - t0.sec_since_epoch()) / rex_return_pool::dist_interval; + }; + + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const time_point_sec effective_time{cts - cts % rex_return_pool::dist_interval}; - if ( ret_pool_elem == _rexretpool.end() || - ct < ret_pool_elem->last_update_time + eosio::microseconds{rex_return_pool::dist_interval}) { + const auto ret_pool_elem = _rexretpool.begin(); + const auto ret_buckets_elem = _rexretbuckets.begin(); + + if ( ret_pool_elem == _rexretpool.end() || effective_time <= ret_pool_elem->last_dist_time ) { return; } - const int64_t current_rate = ret_pool_elem->current_rate_of_increase; - const uint64_t time_interval = ct.time_since_epoch().count() - ret_pool_elem->last_update_time.time_since_epoch().count(); - const int64_t change_estimate = ( uint128_t(time_interval) * current_rate ) / rex_return_pool::total_duration; - const time_point time_threshold = ct - eosio::microseconds{rex_return_pool::total_duration}; + const int64_t current_rate = ret_pool_elem->current_rate_of_increase; + const uint32_t elapsed_intervals = get_elapsed_intervals(effective_time, ret_pool_elem->last_dist_time); + int64_t change_estimate = current_rate * elapsed_intervals; - const bool new_return_bucket = !ret_pool_elem->return_buckets.empty() - && ret_pool_elem->last_update_time <= ret_pool_elem->return_buckets.rbegin()->first - && ret_pool_elem->return_buckets.rbegin()->first <= ct; - int64_t new_bucket_estimate = 0; - if ( new_return_bucket ) { + { + const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; + int64_t new_bucket_rate = 0; + time_point_sec new_bucket_time{0}; _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - rp.current_rate_of_increase += rp.return_buckets.rbegin()->second; - const uint64_t dt = ct.time_since_epoch().count() - rp.return_buckets.rbegin()->first.time_since_epoch().count() ; - new_bucket_estimate = ( uint128_t(dt) * rp.return_buckets.rbegin()->second ) / rex_return_pool::total_duration; + if ( new_return_bucket ) { + int64_t remainder = rp.pending_bucket_proceeds % rex_return_pool::total_intervals; + new_bucket_rate = ( rp.pending_bucket_proceeds - remainder ) / rex_return_pool::total_intervals; + new_bucket_time = rp.pending_bucket_time; + rp.current_rate_of_increase += new_bucket_rate; + change_estimate += remainder + new_bucket_rate * get_elapsed_intervals( effective_time, rp.pending_bucket_time ); + rp.pending_bucket_proceeds = 0; + rp.pending_bucket_time = time_point_sec::maximum(); + if ( new_bucket_time < rp.oldest_bucket_time ) { + rp.oldest_bucket_time = new_bucket_time; + } + } + rp.last_dist_time = effective_time; }); + + if ( new_return_bucket ) { + _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { + rb.return_buckets[new_bucket_time] = new_bucket_rate; + }); + } } - int64_t change = change_estimate + new_bucket_estimate; + const time_point_sec time_threshold = effective_time - eosio::seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); + if ( ret_pool_elem->oldest_bucket_time <= time_threshold ) { + int64_t expired_rate = 0; + int64_t surplus = 0; + _rexretbuckets.modify( ret_buckets_elem, same_payer, [&]( auto& rb ) { + auto& return_buckets = rb.return_buckets; + auto iter = return_buckets.begin(); + while ( iter != return_buckets.end() && iter->first <= time_threshold ) { + auto next = iter; + ++next; + const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + rex_return_pool::total_intervals ); + surplus += iter->second * overtime; + expired_rate += iter->second; + return_buckets.erase(iter); + } + }); - _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - auto& return_buckets = rp.return_buckets; - auto iter = return_buckets.begin(); - while ( iter != return_buckets.end() && iter->first <= time_threshold ) { - auto next = iter; - ++next; - const uint64_t overtime = ct.time_since_epoch().count() - ( iter->first.time_since_epoch().count() + rex_return_pool::total_duration ); - const int64_t rate = iter->second; - const int64_t surplus = ( uint128_t(overtime) * rate + rex_return_pool::total_duration - 1 ) - / rex_return_pool::total_duration; - change -= surplus; - rp.current_rate_of_increase -= rate; - return_buckets.erase(iter); - iter = next; - } - rp.last_update_time = ct; - }); + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { + if ( !ret_buckets_elem->return_buckets.empty() ) { + rp.oldest_bucket_time = ret_buckets_elem->return_buckets.begin()->first; + } else { + rp.oldest_bucket_time = time_point_sec::min(); + } - if ( change <= 0 ) { - return; + if ( expired_rate > 0) { + rp.current_rate_of_increase -= expired_rate; + } + }); + + if ( surplus > 0 ) { + change_estimate -= surplus; + } } - _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { - pool.total_unlent.amount += change; - pool.total_lendable = pool.total_unlent + pool.total_lent; - }); - _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { - rp.cummulative_proceeds += change; - }); + if ( change_estimate > 0 ) { + _rexpool.modify( _rexpool.begin(), same_payer, [&]( auto& pool ) { + pool.total_unlent.amount += change_estimate; + pool.total_lendable = pool.total_unlent + pool.total_lent; + }); + } } template @@ -1029,25 +1059,30 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); + if ( fee.amount <= 0) { + return; + } - const int64_t cts = current_time_point().time_since_epoch().count(); - const int64_t bucket_interval = rex_return_pool::hours_per_bucket * useconds_per_hour; - const time_point effective_time{ eosio::microseconds{cts - cts % bucket_interval + bucket_interval} }; - - if ( _rexretpool.begin() == _rexretpool.end() ) { + const time_point_sec ct = current_time_point(); + const uint32_t cts = ct.sec_since_epoch(); + const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour; + const time_point_sec effective_time{cts - cts % bucket_interval + bucket_interval}; + const auto return_pool_elem = _rexretpool.begin(); + if ( return_pool_elem == _rexretpool.end() ) { _rexretpool.emplace( get_self(), [&]( auto& rp ) { - rp.last_update_time = effective_time; - rp.proceeds += fee.amount; + rp.last_dist_time = effective_time; + rp.pending_bucket_proceeds = fee.amount; + rp.pending_bucket_time = effective_time; }); + _rexretbuckets.emplace( get_self(), [&]( auto& rb ) { } ); } else { - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { - rp.proceeds += fee.amount; + _rexretpool.modify( return_pool_elem, same_payer, [&]( auto& rp ) { + rp.pending_bucket_proceeds += fee.amount; + if ( rp.pending_bucket_time == time_point_sec::maximum() ) { + rp.pending_bucket_time = effective_time; + } }); } - - _rexretpool.modify( _rexretpool.begin(), same_payer, [&]( auto& rp ) { - rp.return_buckets[effective_time] += fee.amount; - }); } /** From dbf8c45cbc7c196c64e6a03e4dc6ac1a7b3835a6 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 00:47:04 -0500 Subject: [PATCH 15/24] REX changes - tests --- contracts/eosio.system/src/rex.cpp | 18 ++--- tests/eosio.system_tester.hpp | 21 ++++++ tests/eosio.system_tests.cpp | 105 +++++++++++++++++------------ 3 files changed, 94 insertions(+), 50 deletions(-) diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index 663336d2f..c775a25b7 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -6,6 +6,7 @@ namespace eosiosystem { using eosio::current_time_point; using eosio::token; + using eosio::seconds; void system_contract::deposit( const name& owner, const asset& amount ) { @@ -621,8 +622,8 @@ namespace eosiosystem { */ void system_contract::update_rex_pool() { - auto get_elapsed_intervals = [&](const time_point_sec& t1, const time_point_sec& t0) -> uint32_t { - return (t1.sec_since_epoch() - t0.sec_since_epoch()) / rex_return_pool::dist_interval; + auto get_elapsed_intervals = [&]( const time_point_sec& t1, const time_point_sec& t0 ) -> uint32_t { + return ( t1.sec_since_epoch() - t0.sec_since_epoch() ) / rex_return_pool::dist_interval; }; const time_point_sec ct = current_time_point(); @@ -637,13 +638,13 @@ namespace eosiosystem { } const int64_t current_rate = ret_pool_elem->current_rate_of_increase; - const uint32_t elapsed_intervals = get_elapsed_intervals(effective_time, ret_pool_elem->last_dist_time); + const uint32_t elapsed_intervals = get_elapsed_intervals( effective_time, ret_pool_elem->last_dist_time ); int64_t change_estimate = current_rate * elapsed_intervals; { const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; int64_t new_bucket_rate = 0; - time_point_sec new_bucket_time{0}; + time_point_sec new_bucket_time = time_point_sec::min(); _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { if ( new_return_bucket ) { int64_t remainder = rp.pending_bucket_proceeds % rex_return_pool::total_intervals; @@ -667,7 +668,7 @@ namespace eosiosystem { } } - const time_point_sec time_threshold = effective_time - eosio::seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); + const time_point_sec time_threshold = effective_time - seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval); if ( ret_pool_elem->oldest_bucket_time <= time_threshold ) { int64_t expired_rate = 0; int64_t surplus = 0; @@ -677,10 +678,12 @@ namespace eosiosystem { while ( iter != return_buckets.end() && iter->first <= time_threshold ) { auto next = iter; ++next; - const uint32_t overtime = get_elapsed_intervals( effective_time, iter->first + rex_return_pool::total_intervals ); + const uint32_t overtime = get_elapsed_intervals( effective_time, + iter->first + seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval) ); surplus += iter->second * overtime; expired_rate += iter->second; return_buckets.erase(iter); + iter = next; } }); @@ -690,7 +693,6 @@ namespace eosiosystem { } else { rp.oldest_bucket_time = time_point_sec::min(); } - if ( expired_rate > 0) { rp.current_rate_of_increase -= expired_rate; } @@ -1059,7 +1061,7 @@ namespace eosiosystem { void system_contract::add_to_rex_return_pool( const asset& fee ) { update_rex_pool(); - if ( fee.amount <= 0) { + if ( fee.amount <= 0 ) { return; } diff --git a/tests/eosio.system_tester.hpp b/tests/eosio.system_tester.hpp index acf3b6c60..809361e8e 100644 --- a/tests/eosio.system_tester.hpp +++ b/tests/eosio.system_tester.hpp @@ -659,6 +659,27 @@ class eosio_system_tester : public TESTER { return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_pool", data, abi_serializer_max_time ); } + fc::variant get_rex_return_buckets() const { + vector data; + const auto& db = control->db(); + namespace chain = eosio::chain; + const auto* t_id = db.find( boost::make_tuple( config::system_account_name, config::system_account_name, N(retbuckets) ) ); + if ( !t_id ) { + return fc::variant(); + } + + const auto& idx = db.get_index(); + + auto itr = idx.lower_bound( boost::make_tuple( t_id->id, 0 ) ); + if ( itr == idx.end() || itr->t_id != t_id->id || 0 != itr->primary_key ) { + return fc::variant(); + } + + data.resize( itr->value.size() ); + memcpy( data.data(), itr->value.data(), data.size() ); + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "rex_return_buckets", data, abi_serializer_max_time ); + } + void setup_rex_accounts( const std::vector& accounts, const asset& init_balance, const asset& net = core_sym::from_string("80.0000"), diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 63e0f5f91..bea3be00d 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -3889,7 +3889,8 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE( !rex_return_pool.is_null() ); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + int64_t rate = fee.get_amount() / (30 * 144); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(10) ); // alice is finally able to sellrex, she gains the fee paid by bob @@ -3897,8 +3898,7 @@ BOOST_FIXTURE_TEST_CASE( buy_rent_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( 0, get_rex_balance(alice).get_amount() ); auto expected_rex_fund = (init_balance + fee).get_amount(); auto actual_rex_fund = get_rex_fund(alice).get_amount(); - BOOST_REQUIRE_EQUAL( true, within_error( expected_rex_fund, actual_rex_fund, 2 ) ); - BOOST_TEST_REQUIRE( actual_rex_fund <= expected_rex_fund ); + BOOST_REQUIRE_EQUAL( expected_rex_fund, actual_rex_fund ); // test that carol's resource limits have been updated properly when loan expires BOOST_REQUIRE_EQUAL( init_cpu_limit, get_cpu_limit( carol ) ); BOOST_REQUIRE_EQUAL( init_net_limit, get_net_limit( carol ) ); @@ -4368,10 +4368,9 @@ BOOST_FIXTURE_TEST_CASE( ramfee_namebid_to_rex, eosio_system_tester ) try { produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); - - BOOST_TEST_REQUIRE( within_error( cur_rex_balance.get_amount(), get_rex_pool()["total_lendable"].as().get_amount(), 4 ) ); - BOOST_TEST_REQUIRE( cur_rex_balance.get_amount() >= get_rex_pool()["total_lendable"].as().get_amount() ); - BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), get_rex_pool()["total_unlent"].as() ); + BOOST_REQUIRE_EQUAL( cur_rex_balance, get_rex_pool()["total_lendable"].as() ); + BOOST_REQUIRE_EQUAL( get_rex_pool()["total_lendable"].as(), + get_rex_pool()["total_unlent"].as() ); } FC_LOG_AND_RETHROW() @@ -4804,8 +4803,8 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to const int64_t init_alice_rex_stake = ( eosio::chain::uint128_t(init_rex.get_amount()) * total_lendable ) / total_rex; const asset rex_sell_amount( get_rex_balance(alice).get_amount() / 4, symbol( SY(4,REX) ) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, rex_sell_amount ) ); - BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance( alice ) + rex_sell_amount ); - BOOST_TEST_REQUIRE( within_error( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake( alice ).get_amount(), 2 ) ); + BOOST_REQUIRE_EQUAL( init_rex, get_rex_balance(alice) + rex_sell_amount ); + BOOST_REQUIRE_EQUAL( 3 * init_alice_rex_stake, 4 * get_rex_vote_stake(alice).get_amount() ); BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4884,14 +4883,14 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), stake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 2 ) ); + BOOST_REQUIRE_EQUAL( purchase + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + purchase + rent + rent + to_net_stake + to_cpu_stake) == get_producer_info(producer_names[0])["total_votes"].as_double() ); BOOST_REQUIRE_EQUAL( success(), rentcpu( emily, bob, rent ) ); produce_block( fc::hours(30 * 24 + 13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); BOOST_REQUIRE_EQUAL( success(), unstake( alice, alice, to_net_stake, to_cpu_stake ) ); - BOOST_TEST_REQUIRE( within_error( (purchase + rent + rent + rent).get_amount(), get_rex_vote_stake(alice).get_amount(), 3 ) ); + BOOST_REQUIRE_EQUAL( purchase + rent + rent + rent, get_rex_vote_stake(alice) ); BOOST_TEST_REQUIRE ( stake2votes(init_stake + get_rex_vote_stake(alice) ) == get_producer_info(producer_names[0])["total_votes"].as_double() ); @@ -5160,6 +5159,8 @@ BOOST_FIXTURE_TEST_CASE( b1_vesting, eosio_system_tester ) try { BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { + constexpr uint32_t total_intervals = 30 * 144; + constexpr uint32_t dist_interval = 10 * 60; BOOST_REQUIRE_EQUAL( true, get_rex_return_pool().is_null() ); const asset init_balance = core_sym::from_string("100000.0000"); @@ -5183,16 +5184,17 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); - int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + int64_t rate = fee.get_amount() / total_intervals; + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); - int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - int64_t change = (eosio::chain::uint128_t(t1-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); + int32_t t1 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + int64_t change = rate * ((t1-t0) / dist_interval) + fee.get_amount() % total_intervals; int64_t expected = payment.get_amount() + change; auto rex_pool = get_rex_pool(); @@ -5202,13 +5204,14 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { produce_block( fc::days(25) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); - int64_t t2 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - change = (eosio::chain::uint128_t(t2-t0) * fee.get_amount()) / (30 * 24 * 3600 * 1000000ll); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int64_t t2 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + change = rate * ((t2-t0) / dist_interval) + fee.get_amount() % total_intervals; expected = payment.get_amount() + change; rex_pool = get_rex_pool(); - BOOST_TEST_REQUIRE( within_one( expected, rex_pool["total_lendable"].as().get_amount() ) ); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); produce_blocks( 1 ); produce_block( fc::days(5) ); @@ -5216,12 +5219,11 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); rex_pool = get_rex_pool(); expected = payment.get_amount() + fee.get_amount(); - BOOST_TEST_REQUIRE( within_error( expected, rex_pool["total_lendable"].as().get_amount(), 2 ) ); - BOOST_TEST_REQUIRE( expected >= rex_pool["total_lendable"].as().get_amount() ); + BOOST_REQUIRE_EQUAL( expected, rex_pool["total_lendable"].as().get_amount() ); BOOST_REQUIRE_EQUAL( rex_pool["total_lendable"].as(), rex_pool["total_unlent"].as() ); } @@ -5233,38 +5235,39 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { const asset fee = core_sym::from_string("15.0000"); BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); - int64_t t0 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); + uint32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); produce_block( fc::hours(1) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 1, rex_return_pool["return_buckets"].get_array().size() ); - int64_t t1 = rex_return_pool["last_update_time"].as().time_since_epoch().count(); - BOOST_REQUIRE_EQUAL( t1, t0 + 3600 * 1000000ll + 500000 ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + uint32_t t1 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( t1, t0 + 6 * dist_interval ); produce_block( fc::hours(12) ); BOOST_REQUIRE_EQUAL( success(), rentnet( bob, bob, fee ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( 2, rex_return_pool["return_buckets"].get_array().size() ); - BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( 1, get_rex_return_buckets()["return_buckets"].get_array().size() ); + int64_t rate = 2 * fee.get_amount() / total_intervals; + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::hours(8) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( 2 * fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( rate, rex_return_pool["current_rate_of_increase"].as() ); produce_block( fc::days(30) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( fee.get_amount(), rex_return_pool["current_rate_of_increase"].as() ); + BOOST_REQUIRE_EQUAL( fee.get_amount() / total_intervals, rex_return_pool["current_rate_of_increase"].as() ); BOOST_TEST_REQUIRE( (init_lendable + fee + fee).get_amount() < get_rex_pool()["total_lendable"].as().get_amount() ); produce_block( fc::days(1) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); - BOOST_REQUIRE_EQUAL( 0, rex_return_pool["return_buckets"].get_array().size() ); - BOOST_TEST_REQUIRE( within_error( init_lendable.get_amount() + 3 * fee.get_amount(), - get_rex_pool()["total_lendable"].as().get_amount(), 3 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( init_lendable.get_amount() + 3 * fee.get_amount(), + get_rex_pool()["total_lendable"].as().get_amount() ); } { @@ -5274,24 +5277,42 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_0 = get_rex_pool(); auto rex_return_pool_0 = get_rex_return_pool(); - produce_block( fc::minutes(9) ); + produce_block( fc::minutes(2) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_1 = get_rex_pool(); auto rex_return_pool_1 = get_rex_return_pool(); - BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_update_time"].as().time_since_epoch().count(), - rex_return_pool_1["last_update_time"].as().time_since_epoch().count()); + BOOST_REQUIRE_EQUAL( rex_return_pool_0["last_dist_time"].as().sec_since_epoch(), + rex_return_pool_1["last_dist_time"].as().sec_since_epoch() ); BOOST_REQUIRE_EQUAL( rex_pool_0["total_lendable"].as(), - rex_pool_1["total_lendable"].as()); - produce_block( fc::minutes(1) ); + rex_pool_1["total_lendable"].as() ); + produce_block( fc::minutes(9) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); auto rex_pool_2 = get_rex_pool(); auto rex_return_pool_2 = get_rex_return_pool(); - BOOST_TEST_REQUIRE( rex_return_pool_1["last_update_time"].as().time_since_epoch().count() < - rex_return_pool_2["last_update_time"].as().time_since_epoch().count()); + BOOST_TEST_REQUIRE( rex_return_pool_1["last_dist_time"].as().sec_since_epoch() < + rex_return_pool_2["last_dist_time"].as().sec_since_epoch() ); BOOST_TEST_REQUIRE( rex_pool_1["total_lendable"].as().get_amount() < - rex_pool_2["total_lendable"].as().get_amount()); + rex_pool_2["total_lendable"].as().get_amount() ); + produce_block( fc::days(31) ); + produce_blocks( 1 ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_pool()["current_rate_of_increase"].as() ); } + { + const asset fee = core_sym::from_string("30.0000"); + for ( uint8_t i = 0; i < 5; ++i ) { + BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); + produce_block( fc::days(1) ); + } + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 5, get_rex_return_buckets()["return_buckets"].get_array().size() ); + produce_block( fc::days(30) ); + BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); + BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); + } + } FC_LOG_AND_RETHROW() From 77c5b9a2ccda1c82ade011fb82b076a0d79c5a0c Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 11:16:53 -0500 Subject: [PATCH 16/24] REX changes - updated comments --- .../include/eosio.system/eosio.system.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 4b24caff1..57f1d529e 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -337,11 +337,11 @@ namespace eosiosystem { // `rex_return_pool` structure underlying the rex return pool table. A rex return pool table entry is defined by: // - `version` defaulted to zero, - // - `last_update_time` the last time returns from renting, ram fees, and name bids were added to the rex pool, - // - `current_rate_of_increase` current amount to be added to the rex pool at a rate of per 30 days, - // - `cummulative_proceeds` bookkeeping variable that tracks fees added to rex pool up to current time, - // - `proceeds` bookkeeping variable that tracks fees added to rex return pool up to current time, - // - `return_buckets` 12-hour buckets containing amounts to be added to the rex pool and the times they become effective + // - `last_dist_time` the last time proceeds from renting, ram fees, and name bids were added to the rex pool, + // - `pending_bucket_time` timestamp of the pending 12-hour return bucket, + // - `oldest_bucket_time` cached timestamp of the oldest 12-hour return bucket, + // - `pending_bucket_proceeds` proceeds in the pending 12-hour return bucket, + // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point_sec last_dist_time; @@ -350,15 +350,18 @@ namespace eosiosystem { int64_t pending_bucket_proceeds = 0; int64_t current_rate_of_increase = 0; - static constexpr int32_t total_intervals = 30 * 144; // 30 days - static constexpr int32_t dist_interval = 10 * 60; // 10 minutes - static constexpr uint8_t hours_per_bucket = 12; + static constexpr uint32_t total_intervals = 30 * 144; // 30 days + static constexpr uint32_t dist_interval = 10 * 60; // 10 minutes + static constexpr uint8_t hours_per_bucket = 12; uint64_t primary_key()const { return 0; } }; typedef eosio::multi_index< "rexretpool"_n, rex_return_pool > rex_return_pool_table; + // `rex_return_buckets` structure underlying the rex return buckets table. A rex return buckets table is defined by: + // - `version` defaulted to zero, + // - `return_buckets` buckets of proceeds accumulated in 12-hour intervals struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_buckets { uint8_t version = 0; std::map return_buckets; From d53d2d8f9d5f8441b7710e9ae63f2d2f34738d7e Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 15:20:49 -0500 Subject: [PATCH 17/24] REX changes - additional checks --- .../include/eosio.system/eosio.system.hpp | 5 ++++- contracts/eosio.system/src/rex.cpp | 20 ++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/contracts/eosio.system/include/eosio.system/eosio.system.hpp b/contracts/eosio.system/include/eosio.system/eosio.system.hpp index 57f1d529e..3cfce3f42 100644 --- a/contracts/eosio.system/include/eosio.system/eosio.system.hpp +++ b/contracts/eosio.system/include/eosio.system/eosio.system.hpp @@ -341,7 +341,8 @@ namespace eosiosystem { // - `pending_bucket_time` timestamp of the pending 12-hour return bucket, // - `oldest_bucket_time` cached timestamp of the oldest 12-hour return bucket, // - `pending_bucket_proceeds` proceeds in the pending 12-hour return bucket, - // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool + // - `current_rate_of_increase` the current rate per dist_interval at which proceeds are added to the rex pool, + // - `proceeds` the maximum amount of proceeds that can be added to the rex pool at any given time struct [[eosio::table,eosio::contract("eosio.system")]] rex_return_pool { uint8_t version = 0; time_point_sec last_dist_time; @@ -349,10 +350,12 @@ namespace eosiosystem { time_point_sec oldest_bucket_time = time_point_sec::min(); int64_t pending_bucket_proceeds = 0; int64_t current_rate_of_increase = 0; + int64_t proceeds = 0; static constexpr uint32_t total_intervals = 30 * 144; // 30 days static constexpr uint32_t dist_interval = 10 * 60; // 10 minutes static constexpr uint8_t hours_per_bucket = 12; + static_assert( total_intervals * dist_interval == 30 * seconds_per_day ); uint64_t primary_key()const { return 0; } }; diff --git a/contracts/eosio.system/src/rex.cpp b/contracts/eosio.system/src/rex.cpp index c775a25b7..8e9d881f3 100644 --- a/contracts/eosio.system/src/rex.cpp +++ b/contracts/eosio.system/src/rex.cpp @@ -642,7 +642,7 @@ namespace eosiosystem { int64_t change_estimate = current_rate * elapsed_intervals; { - const bool new_return_bucket = ret_pool_elem->pending_bucket_time < effective_time; + const bool new_return_bucket = ret_pool_elem->pending_bucket_time <= effective_time; int64_t new_bucket_rate = 0; time_point_sec new_bucket_time = time_point_sec::min(); _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { @@ -658,6 +658,7 @@ namespace eosiosystem { rp.oldest_bucket_time = new_bucket_time; } } + rp.proceeds -= change_estimate; rp.last_dist_time = effective_time; }); @@ -696,11 +697,18 @@ namespace eosiosystem { if ( expired_rate > 0) { rp.current_rate_of_increase -= expired_rate; } + if ( surplus > 0 ) { + change_estimate -= surplus; + rp.proceeds += surplus; + } }); + } - if ( surplus > 0 ) { - change_estimate -= surplus; - } + if ( change_estimate > 0 && ret_pool_elem->proceeds < 0 ) { + _rexretpool.modify( ret_pool_elem, same_payer, [&]( auto& rp ) { + change_estimate += rp.proceeds; + rp.proceeds = 0; + }); } if ( change_estimate > 0 ) { @@ -1074,12 +1082,14 @@ namespace eosiosystem { _rexretpool.emplace( get_self(), [&]( auto& rp ) { rp.last_dist_time = effective_time; rp.pending_bucket_proceeds = fee.amount; - rp.pending_bucket_time = effective_time; + rp.pending_bucket_time = effective_time; + rp.proceeds = fee.amount; }); _rexretbuckets.emplace( get_self(), [&]( auto& rb ) { } ); } else { _rexretpool.modify( return_pool_elem, same_payer, [&]( auto& rp ) { rp.pending_bucket_proceeds += fee.amount; + rp.proceeds += fee.amount; if ( rp.pending_bucket_time == time_point_sec::maximum() ) { rp.pending_bucket_time = effective_time; } From 05f75e97c5658a1de4c4df323a76134d7ed6117f Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 18:59:46 -0500 Subject: [PATCH 18/24] REX changes - fix build issues --- tests/eosio.system_tests.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index bea3be00d..a1ba21bda 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4776,9 +4776,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, { producer_names.begin(), producer_names.begin() + 20 } ) ); + vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 20 ) ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4812,7 +4812,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names[0], producer_names[4] } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names[0], producer_names[4] ) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); @@ -4868,7 +4868,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == From 5a5854e47d73e59be49266494b5423a64ebed096 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:08:50 -0500 Subject: [PATCH 19/24] REX changes - fix build issues --- tests/eosio.system_tests.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index a1ba21bda..10581701c 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4776,9 +4776,9 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to } BOOST_REQUIRE_EQUAL( wasm_assert_msg("voter holding REX tokens must vote for at least 21 producers or for a proxy"), - vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 20 ) ) ); + vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 20) ) ); BOOST_REQUIRE_EQUAL( success(), - vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); + vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); @@ -4812,7 +4812,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_block( fc::days(31) ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names[0], producer_names[4] ) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); @@ -4854,7 +4854,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_REQUIRE_EQUAL( get_rex_vote_stake(alice).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); BOOST_REQUIRE_EQUAL( purchase, get_rex_pool()["total_lendable"].as() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names.begin(), producer_names.begin() + 21 } ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_REQUIRE_EQUAL( purchase, get_rex_vote_stake(alice) ); BOOST_REQUIRE_EQUAL( purchase.get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ); @@ -4868,7 +4868,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex_vote, eosio_system_tester, * boost::unit_tes BOOST_TEST_REQUIRE( within_one( curr_rex_pool["total_lendable"].as().get_amount(), init_rex_pool["total_lendable"].as().get_amount() + rent.get_amount() ) ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector( producer_names.begin(), producer_names.begin() + 21 ) ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names.begin(), producer_names.begin() + 21) ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_voter_info(alice)["staked"].as() - init_stake_amount ) ); BOOST_TEST_REQUIRE( within_one( (purchase + rent).get_amount(), get_rex_vote_stake(alice).get_amount() ) ); BOOST_TEST_REQUIRE ( stake2votes(purchase + rent + init_stake) == From 23b6938153253fb335303d1d55801059de68be31 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:38:54 -0500 Subject: [PATCH 20/24] REX changes - tests --- tests/eosio.system_tests.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 10581701c..09d481927 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4033,9 +4033,6 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_claim_rex, eosio_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), sellrex( alice, asset( 3 * get_rex_balance(alice).get_amount() / 4, symbol{SY(4,REX)} ) ) ); BOOST_TEST_REQUIRE( within_one( init_alice_rex.get_amount() / 4, get_rex_balance(alice).get_amount() ) ); - // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ) ); - // BOOST_REQUIRE_EQUAL( init_alice_rex_stake / 4, get_rex_vote_stake( alice ).get_amount() ); - // BOOST_TEST_REQUIRE( within_one( init_alice_rex_stake / 4, get_voter_info(alice)["staked"].as() - init_stake ) ); init_alice_rex = get_rex_balance(alice); BOOST_REQUIRE_EQUAL( success(), sellrex( bob, get_rex_balance(bob) ) ); @@ -4786,7 +4783,11 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); + + produce_blocks( 1 ); produce_block( fc::days(10) ); + produce_blocks( 1 ); + BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); @@ -4794,7 +4795,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); + produce_blocks( 1 ); produce_block( fc::hours(19 * 24 + 23) ); + produce_blocks( 1 ); + BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); @@ -4808,8 +4812,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); - + + produce_blocks( 1 ); produce_block( fc::days(31) ); + produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); From 46a5bd707ed3325ea61ddb8f61c6f0bc90686b7e Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Wed, 11 Dec 2019 19:47:03 -0500 Subject: [PATCH 21/24] REX changes - tests --- tests/eosio.system_tests.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 09d481927..9c9746089 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4818,7 +4818,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, std::vector(producer_names[0], producer_names[4]) ) ); + std::vector two_producers; + two_producers.push_back( producer_names[0] ); + two_producers.push_back( producer_names[4] ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, two_producers ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); From a1b28f03efa3466b28e239325cf0f52e286bdcf3 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Thu, 12 Dec 2019 10:34:37 -0500 Subject: [PATCH 22/24] REX changes - code cleaning --- tests/eosio.system_tests.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index 9c9746089..eca4dcd56 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -4783,11 +4783,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to == get_producer_info(producer_names[20])["total_votes"].as() ); BOOST_REQUIRE_EQUAL( success(), updaterex( alice ) ); - - produce_blocks( 1 ); produce_block( fc::days(10) ); - produce_blocks( 1 ); - BOOST_TEST_REQUIRE( get_producer_info(producer_names[20])["total_votes"].as() < stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) ); @@ -4795,10 +4791,7 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[20])["total_votes"].as() ); - produce_blocks( 1 ); produce_block( fc::hours(19 * 24 + 23) ); - produce_blocks( 1 ); - BOOST_REQUIRE_EQUAL( success(), rexexec( alice, 1 ) ); const asset init_rex = get_rex_balance( alice ); const auto current_rex_pool = get_rex_pool(); @@ -4812,16 +4805,10 @@ BOOST_FIXTURE_TEST_CASE( update_rex, eosio_system_tester, * boost::unit_test::to BOOST_REQUIRE_EQUAL( get_voter_info( alice )["staked"].as(), init_stake + get_rex_vote_stake(alice).get_amount() ); BOOST_TEST_REQUIRE( stake2votes( asset( get_voter_info( alice )["staked"].as(), symbol{CORE_SYM} ) ) == get_producer_info(producer_names[0])["total_votes"].as() ); - - produce_blocks( 1 ); produce_block( fc::days(31) ); - produce_blocks( 1 ); BOOST_REQUIRE_EQUAL( success(), sellrex( alice, get_rex_balance( alice ) ) ); BOOST_REQUIRE_EQUAL( 0, get_rex_balance( alice ).get_amount() ); - std::vector two_producers; - two_producers.push_back( producer_names[0] ); - two_producers.push_back( producer_names[4] ); - BOOST_REQUIRE_EQUAL( success(), vote( alice, two_producers ) ); + BOOST_REQUIRE_EQUAL( success(), vote( alice, { producer_names[0], producer_names[4] } ) ); BOOST_REQUIRE_EQUAL( wasm_assert_msg("must vote for at least 21 producers or for a proxy before buying REX"), buyrex( alice, core_sym::from_string("1.0000") ) ); From 2f5e46c99e4f2c5a6feaf35b4c177072a6c84e81 Mon Sep 17 00:00:00 2001 From: Khaled Al-Hassanieh Date: Fri, 13 Dec 2019 14:41:28 -0500 Subject: [PATCH 23/24] REX changes - arhag's PR review --- tests/eosio.system_tests.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/eosio.system_tests.cpp b/tests/eosio.system_tests.cpp index eca4dcd56..7021e927b 100644 --- a/tests/eosio.system_tests.cpp +++ b/tests/eosio.system_tests.cpp @@ -5175,13 +5175,18 @@ BOOST_FIXTURE_TEST_CASE( rex_return, eosio_system_tester ) try { } { - const asset fee = core_sym::from_string("30.0000"); + const asset fee = core_sym::from_string("30.0000"); + const uint32_t bucket_interval_sec = fc::hours(12).to_seconds(); + const uint32_t current_time_sec = control->pending_block_time().sec_since_epoch(); + const time_point_sec expected_pending_bucket_time{current_time_sec - current_time_sec % bucket_interval_sec + bucket_interval_sec}; BOOST_REQUIRE_EQUAL( success(), rentcpu( bob, bob, fee ) ); auto rex_return_pool = get_rex_return_pool(); BOOST_REQUIRE_EQUAL( false, rex_return_pool.is_null() ); BOOST_REQUIRE_EQUAL( 0, rex_return_pool["current_rate_of_increase"].as() ); BOOST_REQUIRE_EQUAL( 0, get_rex_return_buckets()["return_buckets"].get_array().size() ); - int32_t t0 = rex_return_pool["last_dist_time"].as().sec_since_epoch(); + BOOST_REQUIRE_EQUAL( expected_pending_bucket_time.sec_since_epoch(), + rex_return_pool["pending_bucket_time"].as().sec_since_epoch() ); + int32_t t0 = rex_return_pool["pending_bucket_time"].as().sec_since_epoch(); produce_block( fc::hours(13) ); BOOST_REQUIRE_EQUAL( success(), rexexec( bob, 1 ) ); From 9f491b969c28b9a0c72583bf100e83f976bc0b66 Mon Sep 17 00:00:00 2001 From: arhag Date: Mon, 16 Dec 2019 10:24:15 -0500 Subject: [PATCH 24/24] bump version to v1.8.3 --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e21c73d0c..5783e8319 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(eosio_contracts) set(VERSION_MAJOR 1) set(VERSION_MINOR 8) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) #set(VERSION_SUFFIX develop) if (VERSION_SUFFIX) diff --git a/README.md b/README.md index b98bf5db5..34fb56efd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eosio.contracts -## Version : 1.8.2 +## Version : 1.8.3 The design of the EOSIO blockchain calls for a number of smart contracts that are run at a privileged permission level in order to support functions such as block producer registration and voting, token staking for CPU and network bandwidth, RAM purchasing, multi-sig, etc. These smart contracts are referred to as the bios, system, msig, wrap (formerly known as sudo) and token contracts.