提交 ab60b5eb 编写于 作者: K Khaled Al-Hassanieh

Updated system contract onblock action

上级 5ef1d2f2
......@@ -31,19 +31,14 @@ namespace eosiosystem {
uint64_t total_ram_bytes_reserved = 0;
eosio::asset total_ram_stake;
eosio::asset payment_per_block;
eosio::asset payment_to_eos_bucket;
time first_block_time_in_cycle = 0;
uint32_t blocks_per_cycle = 0;
time last_bucket_fill_time = 0;
block_timestamp last_producer_schedule_update = 0;
eosio::asset eos_bucket;
eosio::asset savings;
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_ram_bytes_reserved)(total_ram_stake)
(payment_per_block)(payment_to_eos_bucket)(first_block_time_in_cycle)(blocks_per_cycle)
(last_bucket_fill_time)(eos_bucket) )
(last_producer_schedule_update)(eos_bucket)(savings) )
};
struct producer_info {
......@@ -52,8 +47,8 @@ namespace eosiosystem {
eosio::public_key producer_key; /// a packed public key object
eosio::asset per_block_payments;
time last_rewards_claim = 0;
time time_became_active = 0;
time last_produced_block_time = 0;
block_timestamp time_became_active = 0;
block_timestamp last_produced_block_time = 0;
uint64_t primary_key()const { return owner; }
double by_votes()const { return -total_votes; }
......@@ -187,11 +182,11 @@ namespace eosiosystem {
void claimrewards( const account_name& owner );
private:
eosio::asset payment_per_block( double rate );
eosio::asset payment_per_block( double rate, const eosio::asset& token_supply );
eosio::asset payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& eos_bucket );
void update_elected_producers(time cycle_time);
void update_elected_producers( block_timestamp timestamp );
// Implementation details:
......
......@@ -4,129 +4,128 @@
namespace eosiosystem {
const int64_t min_daily_tokens = 100;
const double continuous_rate = std::log1p(5);
const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year
const uint32_t blocks_per_hour = 2 * 3600;
eosio::asset system_contract::payment_per_block( double rate ) {
const eosio::asset token_supply = eosio::token( N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name() );
const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount)) / double(blocks_per_year) );
return eosio::asset(payment, system_token_symbol);
}
void system_contract::onblock( block_timestamp timestamp, account_name producer ) {
global_state_singleton gs( _self, _self );
auto parameters = gs.exists() ? gs.get() : get_default_parameters();
if( parameters.first_block_time_in_cycle == 0 ) {
// This is the first time onblock is called in the blockchain.
parameters.last_bucket_fill_time = timestamp;
gs.set( parameters, _self );
update_elected_producers( timestamp );
}
static const uint32_t slots_per_cycle = parameters.blocks_per_cycle;
const uint32_t time_slots = timestamp - parameters.first_block_time_in_cycle;
if (time_slots >= slots_per_cycle) {
auto beginning_of_cycle = timestamp - (time_slots % slots_per_cycle);
update_elected_producers(beginning_of_cycle);
}
producers_table producers_tbl( _self, _self );
const asset block_payment = parameters.payment_per_block;
auto prod = producers_tbl.find(producer);
if ( prod != producers_tbl.end() ) {
producers_tbl.modify( prod, 0, [&](auto& p) {
p.per_block_payments += block_payment;
p.last_produced_block_time = timestamp;
});
}
const uint32_t num_of_payments = timestamp - parameters.last_bucket_fill_time;
const asset to_eos_bucket = num_of_payments * parameters.payment_to_eos_bucket;
parameters.last_bucket_fill_time = timestamp;
parameters.eos_bucket += to_eos_bucket;
gs.set( parameters, _self );
}
eosio::asset system_contract::payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& eos_bucket ) {
eosio::asset payment(0, S(4,EOS));
if (eos_bucket < threshold) {
return payment;
const int64_t min_daily_tokens = 100;
const double continuous_rate = std::log1p(0.05); // 5% annual rate
const double per_block_rate = 0.0025; // 0.25%
const double standby_rate = 0.0075; // 0.75%
const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year
const uint32_t blocks_per_hour = 2 * 3600;
eosio::asset system_contract::payment_per_block( double rate, const eosio::asset& token_supply ) {
const int64_t payment = static_cast<int64_t>( (rate * double(token_supply.amount)) / double(blocks_per_year) );
return eosio::asset( payment, token_supply.symbol );
}
auto idx = _producers.template get_index<N(prototalvote)>();
double total_producer_votes = 0;
double running_payment_amount = 0;
bool to_be_payed = false;
for ( auto itr = idx.begin(); itr != idx.end(); ++itr ) {
if ( !(itr->total_votes > 0) ) {
break;
}
if ( !(itr->active()) && !(itr->owner != owner) ) {
continue;
void system_contract::onblock( block_timestamp timestamp, account_name producer ) {
using namespace eosio;
const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() );
const asset issued = payment_per_block( continuous_rate, token_supply );
const asset producer_payment = payment_per_block( per_block_rate, token_supply );
const asset to_eos_bucket = payment_per_block( standby_rate, token_supply );
const asset to_savings = issued - (producer_payment + to_eos_bucket);
INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}},
{N(eosio), issued, std::string("issue tokens per block")} );
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {{N(eosio),N(active)}},
{N(eosio), N(eosio), to_savings, std::string("transfer to savings per block")} );
// update producer info and balance
auto prod = _producers.find(producer);
if ( prod != _producers.end() ) {
_producers.modify( prod, 0, [&](auto& p) {
p.per_block_payments += producer_payment;
p.last_produced_block_time = timestamp;
});
}
if ( itr->owner == owner ) {
to_be_payed = true;
auto parameters = _global.exists() ? _global.get() : get_default_parameters();
parameters.eos_bucket += to_eos_bucket;
parameters.savings += to_savings;
_global.set ( parameters, _self );
const auto& producer_schedule_update = parameters.last_producer_schedule_update;
if ( producer_schedule_update == 0 || producer_schedule_update < timestamp + blocks_per_hour ) {
update_elected_producers( producer_schedule_update );
}
total_producer_votes += itr->total_votes;
running_payment_amount = (itr->total_votes) * double(eos_bucket.amount) / total_producer_votes;
if ( running_payment_amount < min_daily_tokens ) {
}
eosio::asset system_contract::payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& eos_bucket ) {
eosio::asset payment(0, S(4,EOS));
if ( eos_bucket.amount < min_daily_tokens ) {
return payment;
}
auto idx = _producers.template get_index<N(prototalvote)>();
double total_producer_votes = 0;
double running_payment_amount = 0;
bool to_be_payed = false;
for ( auto itr = idx.cbegin(); itr != idx.cend(); ++itr ) {
if ( !(itr->total_votes > 0) ) {
break;
}
if ( !(itr->active()) && !(itr->owner != owner) ) {
continue;
}
if ( itr->owner == owner ) {
to_be_payed = false;
to_be_payed = true;
}
total_producer_votes += itr->total_votes;
running_payment_amount = (itr->total_votes) * double(eos_bucket.amount) / total_producer_votes;
if ( running_payment_amount < min_daily_tokens ) {
if ( itr->owner == owner ) {
to_be_payed = false;
}
total_producer_votes -= itr->total_votes;
break;
}
total_producer_votes -= itr->total_votes;
break;
}
if ( to_be_payed ) {
payment.amount = static_cast<int64_t>( (double(eos_bucket.amount) * owners_votes) / total_producer_votes );
}
return payment;
}
if ( to_be_payed ) {
payment.amount = static_cast<int64_t>( (double(eos_bucket.amount) * owners_votes) / total_producer_votes );
}
return payment;
}
void system_contract::claimrewards( const account_name& owner ) {
require_auth(owner);
producers_table producers_tbl( _self, _self );
auto prod = producers_tbl.find( owner );
eosio_assert(prod != producers_tbl.end(), "account name is not in producer list");
if( prod->last_rewards_claim > 0 ) {
eosio_assert(now() >= prod->last_rewards_claim + seconds_per_day, "already claimed rewards within a day");
}
eosio::asset rewards = prod->per_block_payments;
global_state_singleton gs( _self, _self );
if ( gs.exists() ) {
auto parameters = gs.get();
if ( parameters.eos_bucket.amount > 0 && prod->total_votes > 0 ) {
eosio::asset standby_payment = payment_per_vote( owner, prod->total_votes, parameters.eos_bucket );
if ( standby_payment.amount > 0 ) {
rewards += standby_payment;
parameters.eos_bucket -= standby_payment;
gs.set( parameters, _self );
void system_contract::claimrewards( const account_name& owner ) {
require_auth(owner);
auto prod = _producers.find( owner );
eosio_assert( prod != _producers.end(), "account name is not in producer list" );
if( prod->last_rewards_claim > 0 ) {
eosio_assert(now() >= prod->last_rewards_claim + seconds_per_day, "already claimed rewards within a day");
}
eosio::asset rewards = prod->per_block_payments;
if ( _global.exists() ) {
auto parameters = _global.get();
if ( parameters.eos_bucket.amount > 0 && prod->total_votes > 0 ) {
eosio::asset standby_payment = payment_per_vote( owner, prod->total_votes, parameters.eos_bucket );
if ( standby_payment.amount > 0 ) {
rewards += standby_payment;
parameters.eos_bucket -= standby_payment;
_global.set( parameters, _self );
}
}
}
eosio_assert( rewards > asset(0, S(4,EOS)), "no rewards available to claim" );
_producers.modify( prod, 0, [&](auto& p) {
p.last_rewards_claim = now();
p.per_block_payments.amount = 0;
});
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
{ N(eosio), owner, rewards, std::string("producer claiming rewards") } );
}
eosio_assert( rewards > asset(0, S(4,EOS)), "no rewards available to claim" );
producers_tbl.modify( prod, 0, [&](auto& p) {
p.last_rewards_claim = now();
p.per_block_payments.amount = 0;
});
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
{ N(eosio), owner, rewards, std::string("producer claiming rewards") } );
}
} //namespace eosiosystem
......@@ -26,10 +26,6 @@ namespace eosiosystem {
using eosio::singleton;
using eosio::transaction;
static constexpr uint32_t blocks_per_producer = 12;
/**
* This method will create a producer_config and producer_info object for 'producer'
*
......@@ -70,7 +66,7 @@ namespace eosiosystem {
});
}
void system_contract::update_elected_producers(time cycle_time) {
void system_contract::update_elected_producers(block_timestamp block_time) {
auto idx = _producers.get_index<N(prototalvote)>();
eosio::producer_schedule schedule;
......@@ -93,19 +89,7 @@ namespace eosiosystem {
set_active_producers( packed_schedule.data(), packed_schedule.size() );
// not voted on
_gstate.first_block_time_in_cycle = cycle_time;
// derived parameters
auto half_of_percentage = _gstate.percent_of_max_inflation_rate / 2;
auto other_half_of_percentage = _gstate.percent_of_max_inflation_rate - half_of_percentage;
_gstate.payment_per_block = payment_per_block(half_of_percentage);
_gstate.payment_to_eos_bucket = payment_per_block(other_half_of_percentage);
_gstate.blocks_per_cycle = blocks_per_producer * schedule.producers.size();
auto issue_quantity =_gstate.blocks_per_cycle * (_gstate.payment_per_block +_gstate.payment_to_eos_bucket);
INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}},
{N(eosio), issue_quantity, std::string("producer pay")} );
_gstate.last_producer_schedule_update = block_time;
}
/**
......@@ -220,4 +204,4 @@ namespace eosiosystem {
});
}
}
} /// namespace eosiosystem
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册