diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi index 0e85935aba82b3a00aaeb6bd9ab9c606eaee5b35..5e479f41068bc0d2b5a14290368e1e6f4042ad8e 100644 --- a/contracts/eosio.system/eosio.system.abi +++ b/contracts/eosio.system/eosio.system.abi @@ -116,8 +116,7 @@ "name": "eosio_parameters", "base": "blockchain_parameters", "fields": [ - {"name":"max_ram_size", "type":"uint64"}, - {"name":"percent_of_max_inflation_rate", "type":"uint32"} + {"name":"max_ram_size", "type":"uint64"} ] },{ "name": "eosio_global_state", diff --git a/contracts/eosio.system/producer_pay.cpp b/contracts/eosio.system/producer_pay.cpp index 4f2cd0ac14fb2ab3bbbe5749445d3c7b3c01c54c..c69f5e2c036b2f5cf063d6ed90151ff992a3e4aa 100644 --- a/contracts/eosio.system/producer_pay.cpp +++ b/contracts/eosio.system/producer_pay.cpp @@ -33,7 +33,7 @@ namespace eosiosystem { return; if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses - _gstate.last_pervote_bucket_fill = timestamp; + _gstate.last_pervote_bucket_fill = current_time(); auto prod = _producers.find(producer); if ( prod != _producers.end() ) { @@ -102,9 +102,8 @@ namespace eosiosystem { eosio_assert(current_time() >= prod->last_claim_time + useconds_per_day, "already claimed rewards within a day"); } - auto parameters = _global.get(); const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() ); - const uint32_t secs_since_last_fill = static_cast( (current_time() - parameters.last_pervote_bucket_fill) / 1000000 ); + const uint32_t secs_since_last_fill = static_cast( (current_time() - _gstate.last_pervote_bucket_fill) / 1000000 ); const asset to_eos_bucket = supply_growth( standby_rate, token_supply, secs_since_last_fill ); const asset to_savings = supply_growth( continuous_rate - (perblock_rate + standby_rate), token_supply, secs_since_last_fill ); @@ -114,12 +113,11 @@ namespace eosiosystem { INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, {N(eosio), issue_amount, std::string("issue tokens for producer pay and savings")} ); - const asset pervote_pay = payment_per_vote( owner, prod->total_votes, to_eos_bucket + parameters.eos_bucket ); + const asset pervote_pay = payment_per_vote( owner, prod->total_votes, to_eos_bucket + _gstate.eos_bucket ); - parameters.eos_bucket += ( to_eos_bucket - pervote_pay ); - parameters.last_pervote_bucket_fill = current_time(); - parameters.savings += to_savings; - _global.set( parameters, _self ); + _gstate.eos_bucket += ( to_eos_bucket - pervote_pay ); + _gstate.last_pervote_bucket_fill = current_time(); + _gstate.savings += to_savings; INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, { N(eosio), owner, perblock_pay + pervote_pay, std::string("producer claiming rewards") } ); diff --git a/unittests/eosio.system_tests.cpp b/unittests/eosio.system_tests.cpp index 8d180c22707b029814dacae26322c0709016e24c..d23573de57b8bc7489182e48441e933191105655 100644 --- a/unittests/eosio.system_tests.cpp +++ b/unittests/eosio.system_tests.cpp @@ -45,8 +45,6 @@ public: issue(config::system_account_name, "1000000000.0000 EOS"); BOOST_REQUIRE_EQUAL( asset::from_string("1000000000.0000 EOS"), get_balance( "eosio" ) ); - // create_accounts_with_resources ( { N(inita), N(initb), N(voter1), N(voter2) }, asset::from_string("100000.0000 EOS") ); - set_code( config::system_account_name, eosio_system_wast ); set_abi( config::system_account_name, eosio_system_abi ); @@ -62,10 +60,18 @@ public: produce_blocks(); - const auto& accnt = control->db().get( config::system_account_name ); - abi_def abi; - BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); - abi_ser.set_abi(abi); + { + const auto& accnt = control->db().get( config::system_account_name ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + abi_ser.set_abi(abi); + } + { + const auto& accnt = control->db().get( N(eosio.token) ); + abi_def abi; + BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true); + token_abi_ser.set_abi(abi); + } /* const global_property_object &gpo = control->get_global_properties(); FC_ASSERT(0 < gpo.active_producers.producers.size(), "No producers"); @@ -311,8 +317,25 @@ public: ); } + fc::variant get_stats( const string& symbolname ) { + auto symb = eosio::chain::symbol::from_string(symbolname); + auto symbol_code = symb.to_symbol_code().value; + vector data = get_row_by_account( N(eosio.token), symbol_code, N(stat), symbol_code ); + return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data ); + } + + asset get_token_supply() { + return get_stats("4,EOS")["supply"].as(); + } + + fc::variant get_global_state() { + vector data = get_row_by_account( N(eosio), N(eosio), N(global), N(global) ); + if (data.empty()) std::cout << "\nData is empty\n" << std::endl; + return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data ); + } abi_serializer abi_ser; + abi_serializer token_abi_ser; }; fc::mutable_variant_object voter( account_name acct ) { @@ -1180,7 +1203,6 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try { produce_block(); - // 1 block produced BOOST_REQUIRE_EQUAL(success(), regproducer(N(inita))); auto prod = get_producer_info( N(inita) ); @@ -1197,19 +1219,66 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try { ) ); - produce_blocks(200); - prod = get_producer_info("inita"); - - BOOST_REQUIRE(1 < prod["produced_blocks"].as()); - BOOST_REQUIRE_EQUAL(success(), push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); - - prod = get_producer_info("inita"); - BOOST_REQUIRE_EQUAL(1, prod["produced_blocks"].as()); + // inita is the only active producer + // produce enough blocks so new schedule kicks in and inita produces some blocks + { + produce_blocks(50); + + const auto initial_global_state = get_global_state(); + const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); + const asset initial_eos_bucket = initial_global_state["eos_bucket"].as(); + const asset initial_savings = initial_global_state["savings"].as(); + prod = get_producer_info("inita"); + const uint32_t produced_blocks = prod["produced_blocks"].as(); + BOOST_REQUIRE(1 < produced_blocks); + BOOST_REQUIRE_EQUAL(0, prod["last_claim_time"].as()); + const asset initial_supply = get_token_supply(); + const asset initial_balance = get_balance(N(inita)); + + BOOST_REQUIRE_EQUAL(success(), push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); + + const auto global_state = get_global_state(); + const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); + const asset eos_bucket = global_state["eos_bucket"].as(); + const asset savings = global_state["savings"].as(); + prod = get_producer_info("inita"); + BOOST_REQUIRE_EQUAL(1, prod["produced_blocks"].as()); + const asset supply = get_token_supply(); + const asset balance = get_balance(N(inita)); + + BOOST_REQUIRE_EQUAL(claim_time, prod["last_claim_time"].as()); + const int32_t secs_between_fills = static_cast((claim_time - initial_claim_time) / 1000000); + + BOOST_REQUIRE_EQUAL(0, initial_eos_bucket.amount); + BOOST_REQUIRE_EQUAL(0, eos_bucket.amount); + BOOST_REQUIRE_EQUAL(int64_t( (initial_supply.amount * secs_between_fills * ((4.879-1.0)/100.0)) / (52*7*24*3600) ), + savings.amount - initial_savings.amount); + + int64_t block_payments = int64_t( initial_supply.amount * produced_blocks * (0.25/100.0) / (52*7*24*3600*2) ); + int64_t from_eos_bucket = int64_t( initial_supply.amount * secs_between_fills * (0.75/100.0) / (52*7*24*3600) ); + + BOOST_REQUIRE_EQUAL(block_payments + from_eos_bucket, balance.amount - initial_balance.amount); + } + + { + BOOST_REQUIRE_EQUAL(error("condition: assertion failed: already claimed rewards within a day"), + push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); + } - BOOST_REQUIRE_EQUAL(error("condition: assertion failed: already claimed rewards within a day"), - push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); + // inita waits for 23 hours and 55 minutes, can't claim rewards yet + { + produce_block(fc::seconds(23 * 3600 + 55 * 60)); + BOOST_REQUIRE_EQUAL(error("condition: assertion failed: already claimed rewards within a day"), + push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); + } - produce_block(fc::seconds(1)); + // wait 5 more minutes, inita can now claim rewards again + { + produce_block(fc::seconds(5 * 60)); + BOOST_REQUIRE_EQUAL(success(), + push_action(N(inita), N(claimrewards), mvo()("owner", "inita"))); + BOOST_REQUIRE_EQUAL(1, prod["produced_blocks"].as()); + } } FC_LOG_AND_RETHROW()