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

Producer pay fixes, token issuing

上级 1a60535a
......@@ -13,34 +13,36 @@ namespace eosiosystem {
public:
static constexpr account_name system_account = SystemAccount;
typedef eosio::generic_currency< eosio::token<system_account,S(4,EOS)> > currency;
typedef typename currency::token_type system_token_type;
static constexpr uint64_t currency_symbol = currency::symbol; // S(4,EOS)
static constexpr uint8_t currency_decimals = currency_symbol & 0xFF; // 4
static const uint32_t max_inflation_rate = 5; // 5% annual inflation
#warning "change to config parameter"
static constexpr uint32_t producer_repititions = 12;
static constexpr uint32_t blocks_per_cycle = 21 * producer_repititions;
static const uint32_t mseconds_per_day = 24 * 3600 * 1000;
static constexpr uint32_t days_per_4years = 1461;
typedef typename currency::token_type system_token_type;
static constexpr uint64_t currency_symbol = currency::symbol; // S(4,EOS)
static constexpr uint8_t currency_decimals = currency_symbol & 0xFF; // 4
static const uint32_t max_inflation_rate = 5; // 5% annual inflation
static const uint32_t blocks_per_producer = 6;
static const uint32_t seconds_per_day = 24 * 3600;
static constexpr uint32_t days_per_4years = 1461;
struct eosio_parameters : eosio::blockchain_parameters {
uint32_t percent_of_max_inflation_rate = 0; // inflation coefficient * 10000 (i.e. inflation in percent * 100)
uint32_t percent_of_max_inflation_rate = 0;
uint32_t storage_reserve_ratio = 1000; // ratio * 1000
EOSLIB_SERIALIZE_DERIVED( eosio_parameters, eosio::blockchain_parameters, (percent_of_max_inflation_rate)(storage_reserve_ratio) )
};
struct eosio_global_state : eosio_parameters {
uint64_t total_storage_bytes_reserved = 0;
system_token_type total_storage_stake;
system_token_type payment_per_block = system_token_type();
system_token_type payment_to_eos_bucket = system_token_type();
time first_block_time_in_cycle = 0;
time last_bucket_fill_time = 0;
system_token_type eos_bucket = system_token_type();
uint64_t total_storage_bytes_reserved = 0;
system_token_type total_storage_stake;
system_token_type payment_per_block = system_token_type();
system_token_type payment_to_eos_bucket = system_token_type();
time first_block_time_in_cycle = 0;
uint32_t blocks_per_cycle = 0; //6 * 21;
time last_bucket_fill_time = 0;
system_token_type eos_bucket = system_token_type();
EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio_parameters, (total_storage_bytes_reserved)(total_storage_stake)
(payment_per_block)(payment_to_eos_bucket)(first_block_time_in_cycle)(last_bucket_fill_time)(eos_bucket) )
(payment_per_block)(payment_to_eos_bucket)(first_block_time_in_cycle)(blocks_per_cycle)
(last_bucket_fill_time)(eos_bucket) )
};
typedef eosio::singleton<SystemAccount, N(inflation), SystemAccount, eosio_global_state> global_state_singleton;
......@@ -56,8 +58,8 @@ namespace eosiosystem {
static const uint64_t denom = 10000;
uint64_t ret = 0;
uint64_t x_power = x;
const uint8_t n = 4;
static constexpr uint64_t ten_power = denom * denom * denom * denom;
const uint64_t n = 4;
static const uint64_t ten_power = denom * denom * denom * denom;
for (uint64_t i = 0, p = ten_power; i < n; ++i) {
uint64_t factor = x_power * p / (i+1);
ret += factor;
......@@ -65,7 +67,7 @@ namespace eosiosystem {
x_power *= x;
p /= denom;
}
return std::make_pair(ret * denom/ten_power, denom);
return std::make_pair(ret / (denom * denom * denom), denom);
}
}
......@@ -92,7 +92,7 @@
{"name":"max_inline_depth", "type":"uint16"},
{"name":"max_inline_action_size", "type":"uint32"},
{"name":"max_generated_transaction_size", "type":"uint32"},
{"name":"inflation_rate", "type":"uint32"},
{"name":"percent_of_max_inflation_rate", "type":"uint32"},
{"name":"storage_reserve_ratio", "type":"uint32"}
]
},{
......@@ -100,16 +100,19 @@
"base": "eosio_parameters",
"fields": [
{"name":"total_storage_bytes_reserved", "type":"uint64"},
{"name":"total_storage_stake", "type":"uint64"}
{"name":"total_storage_stake", "type":"uint64"},
{"name":"payment_per_block", "type":"uint64"}
]
},{
"name": "producer_info",
"base": "",
"fields": [
{"name":"owner", "type":"uint64"},
{"name":"total_votes", "type":"uint128"},
{"name":"prefs", "type":"eosio_parameters"},
{"name":"packed_key", "type":"uint8[]"}
{"name":"owner", "type":"uint64"},
{"name":"total_votes", "type":"uint128"},
{"name":"prefs", "type":"eosio_parameters"},
{"name":"packed_key", "type":"uint8[]"},
{"name":"per_block_payments", "type":"uint64"},
{"name":"last_claim_time", "type":"uint32"}
]
},{
"name": "regproducer",
......@@ -149,6 +152,12 @@
{"name":"deferred_trx_id", "type":"uint32"},
{"name":"last_unstake", "type":"uint32"}
]
},{
"name": "claimrewards",
"base": "",
"fields": [
{"name":"owner", "type":"account_name"}
]
}
],
"actions": [{
......@@ -172,6 +181,9 @@
},{
"name": "voteproducer",
"type": "voteproducer"
},{
"name": "claimrewards",
"type": "claimrewards"
}
],
"tables": [
......
......@@ -11,21 +11,7 @@
#include <eosiolib/generic_currency.hpp>
namespace eosiosystem {
/*
struct PACKED(producer_key) {
account_name producer_name;
public_key block_signing_key;
EOSLIB_SERIALIZE(producer_key, (producer_name)(block_signing_key))
};
struct PACKED(producer_schedule) {
uint32_t version;
std::vector<producer_key> producers;
EOSLIB_SERIALIZE(producer_schedule, (version)(producers))
};
*/
struct PACKED(block_header) {
checksum256 previous;
time timestamp;
......@@ -49,9 +35,10 @@ namespace eosiosystem {
using system_token_type = typename common<SystemAccount>::system_token_type;
using producers_table = typename pe::producers_table;
using global_state_singleton = typename voting<SystemAccount>::global_state_singleton;
// using mseconds_per_day = typename common<SystemAccount>::mseconds_per_day;
static const uint32_t max_inflation_rate = common<SystemAccount>::max_inflation_rate;
static const uint32_t mseconds_per_day = common<SystemAccount>::mseconds_per_day;
static const uint32_t seconds_per_day = common<SystemAccount>::seconds_per_day;
static const uint32_t num_of_payed_producers = 121;
static const uint32_t slot = 1;
ACTION( SystemAccount, nonce ) {
eosio::string value;
......@@ -63,46 +50,24 @@ namespace eosiosystem {
}
static bool update_cycle(time block_time) {
auto parameters = global_state_singleton::exists() ? global_state_singleton::get()
: common<SystemAccount>::get_default_parameters();
auto parameters = global_state_singleton::exists() ? global_state_singleton::get()
: common<SystemAccount>::get_default_parameters();
if (parameters.first_block_time_in_cycle == 0) {
voting<SystemAccount>::update_elected_producers(block_time);
return true;
}
static const time slot = 500;
static const uint32_t slots_per_cycle = common<SystemAccount>::blocks_per_cycle;
const time delta = block_time - parameters.first_block_time_in_cycle;
uint32_t time_slots = delta / slot;
if (time_slots >= common<SystemAccount>::blocks_per_cycle) {
time beginning_of_cycle = block_time - (time_slots % slots_per_cycle) * slot;
static const uint32_t slots_per_cycle = parameters.blocks_per_cycle;
const uint32_t time_slots = block_time - parameters.first_block_time_in_cycle;
if (time_slots >= slots_per_cycle) {
time beginning_of_cycle = block_time - (time_slots % slots_per_cycle);
voting<SystemAccount>::update_elected_producers(beginning_of_cycle);
return true;
}
return false;
}
/*
static system_token_type daily_payment(uint32_t percent_of_max_inflation_rate)
{
const system_token_type token_supply = currency::get_total_supply();
const auto inflation_rate = max_inflation_rate * percent_of_max_inflation_rate;
const auto& inflation_ratio = int_logarithm_one_plus(inflation_rate);
return ((token_supply * inflation_ratio.first * 4) /
(inflation_ratio.second * common<SystemAccount>::days_per_4years));
}
static void fill_eos_bucket(time block_time) {
auto parameters = global_state_singleton::get();
const time delta = block_time - parameters.last_bucket_fill_time;
if (delta >= mseconds_per_day) {
parameters.last_bucket_fill_time = parameters.last_bucket_fill_time + mseconds_per_day;
uint32_t percent = parameters.percent_of_max_inflation_rate - parameters.percent_of_max_inflation_rate / 2;
parameters.eos_bucket += daily_payment(percent);
global_state_singleton::set(parameters);
}
}
*/
ACTION(SystemAccount, onblock) {
block_header header;
......@@ -111,7 +76,9 @@ namespace eosiosystem {
static void on(const onblock& ob) {
// update parameters if it's a new cycle
update_cycle(ob.header.timestamp);
if (update_cycle(ob.header.timestamp)) {
// prints("\nNew Cycle!\n\n");
}
producers_table producers_tbl(SystemAccount, SystemAccount);
account_name producer = ob.header.producer;
auto parameters = global_state_singleton::exists() ? global_state_singleton::get()
......@@ -119,36 +86,44 @@ namespace eosiosystem {
const system_token_type block_payment = parameters.payment_per_block;
const auto* prod = producers_tbl.find(producer);
// This check is needed when everything works
// eosio_assert(prod != nullptr, "something wrong here");
// eosio_assert(prod != nullptr, "something wrong here");
if (prod != nullptr) {
// prints("Producer found\n");
producers_tbl.update(*prod, 0, [&](auto& p) {
// printi((uint64_t)p.per_block_payments.quantity);
// prints("\n");
p.per_block_payments += block_payment;
// printi((uint64_t)p.per_block_payments.quantity);
// prints("\n");
p.last_produced_block_time = ob.header.timestamp;
});
}
const uint32_t num_of_payments = (ob.header.timestamp - parameters.last_bucket_fill_time) / 500;
// prints("payments to eos bucket\n");
const uint32_t num_of_payments = ob.header.timestamp - parameters.last_bucket_fill_time;
const system_token_type to_eos_bucket = num_of_payments * parameters.payment_to_eos_bucket;
// printi(to_eos_bucket.quantity);
// prints("\n");
parameters.last_bucket_fill_time = ob.header.timestamp;
parameters.eos_bucket += to_eos_bucket;
global_state_singleton::set(parameters);
}
ACTION(SystemAccount, claim_rewards) {
ACTION(SystemAccount, claimrewards) {
account_name owner;
time claim_time;
EOSLIB_SERIALIZE(claim_rewards, (owner)(claim_time))
EOSLIB_SERIALIZE(claimrewards, (owner))
};
static void on(const claim_rewards& cr) {
static void on(const claimrewards& cr) {
require_auth(cr.owner);
eosio_assert(current_sender() == account_name(), "claimrewards can not be part of a deferred transaction");
producers_table producers_tbl(SystemAccount, SystemAccount);
const auto* prod = producers_tbl.find(cr.owner);
eosio_assert(prod != nullptr, "account name not proucer list");
eosio_assert(prod != nullptr, "account name not producer list");
eosio_assert(prod->active(), "producer is not active");
const time ctime = cr.claim_time;
if (prod->last_rewards_claim > 0) {
eosio_assert(ctime >= prod->last_rewards_claim + mseconds_per_day, "already claimed rewards today");
eosio_assert(now() >= prod->last_rewards_claim + seconds_per_day, "already claimed rewards within a day");
}
system_token_type rewards = prod->per_block_payments;
auto idx = producers_tbl.template get_index<N(prototalvote)>();
......@@ -156,13 +131,15 @@ namespace eosiosystem {
bool is_among_payed_producers = false;
uint64_t total_producer_votes = 0;
for (uint32_t i = 0; i < 121; ++i) {
uint32_t n = 0;
while (n < num_of_payed_producers) {
if (!is_among_payed_producers) {
if (itr->owner == cr.owner)
is_among_payed_producers = true;
}
if (itr->active()) {
total_producer_votes += itr->total_votes;
++n;
}
if (itr == idx.begin()) {
break;
......@@ -170,14 +147,20 @@ namespace eosiosystem {
--itr;
}
if (is_among_payed_producers) {
const system_token_type eos_bucket = global_state_singleton::get_or_default().eos_bucket;
rewards += (uint64_t(prod->total_votes) * eos_bucket) / total_producer_votes;
if (is_among_payed_producers && total_producer_votes > 0) {
if (global_state_singleton::exists()) {
auto parameters = global_state_singleton::get();
auto share_of_eos_bucket = (uint64_t(prod->total_votes) * parameters.eos_bucket) / total_producer_votes;
rewards += share_of_eos_bucket;
parameters.eos_bucket -= share_of_eos_bucket;
global_state_singleton::set(parameters);
}
}
producers_tbl.update(*prod, 0, [&](auto& p) {
p.last_rewards_claim = ctime;
p.per_block_payments = system_token_type();
p.last_rewards_claim = now();
p.per_block_payments.quantity = 0;
});
currency::inline_transfer(cr.owner, SystemAccount, rewards, "producer claiming rewards");
}
......@@ -192,7 +175,7 @@ namespace eosiosystem {
typename voting<SystemAccount>::voteproducer,
typename voting<SystemAccount>::unstake_vote_deferred,
onblock,
claim_rewards,
claimrewards,
nonce>( code, act) ) {
eosio::print("Unexpected action: ", eosio::name(act), "\n");
eosio_assert( false, "received unexpected action");
......
......@@ -39,6 +39,7 @@ namespace eosiosystem {
using global_state_singleton = typename common<SystemAccount>::global_state_singleton;
static const uint32_t max_inflation_rate = common<SystemAccount>::max_inflation_rate;
// static const uint32_t blocks_per_cycle = common<SystemAccount>::blocks_per_cycle;
static constexpr uint32_t max_unstake_requests = 10;
static constexpr uint32_t unstake_pay_period = 7*24*3600; // one per week
static constexpr uint32_t unstake_payments = 26; // during 26 weeks
......@@ -256,8 +257,21 @@ namespace eosiosystem {
static system_token_type payment_per_block(uint32_t percent_of_max_inflation_rate) {
const system_token_type token_supply = currency::get_total_supply();
/*
prints("token_supply\n");
printi(token_supply.quantity);
prints("\ntoken_supply\n");
*/
const auto inflation_rate = max_inflation_rate * percent_of_max_inflation_rate;
const auto& inflation_ratio = int_logarithm_one_plus(inflation_rate);
/*
printi(inflation_rate);
prints("\n");
printi(inflation_ratio.first);
prints("/");
printi(inflation_ratio.second);
prints("\n");
*/
return (token_supply * inflation_ratio.first) / (inflation_ratio.second * blocks_per_year);
}
......@@ -356,14 +370,16 @@ namespace eosiosystem {
auto other_half_of_percentage = parameters.percent_of_max_inflation_rate - half_of_percentage;
parameters.payment_per_block = payment_per_block(half_of_percentage);
parameters.payment_to_eos_bucket = payment_per_block(other_half_of_percentage);
parameters.blocks_per_cycle = 6 * schedule.producers.size();
if ( parameters.max_storage_size < parameters.total_storage_bytes_reserved ) {
parameters.max_storage_size = parameters.total_storage_bytes_reserved;
}
auto issue_quantity = parameters.blocks_per_cycle * (parameters.payment_per_block + parameters.payment_to_eos_bucket);
currency::inline_issue(SystemAccount, issue_quantity);
set_blockchain_parameters(&parameters);
global_state_singleton::set( parameters );
global_state_singleton::set(parameters);
}
ACTION( SystemAccount, unstake_vote_deferred ) {
......
......@@ -21,6 +21,9 @@ namespace eosio {
ACTION( code, issue ) {
typedef action_meta<code,N(issue)> meta;
issue() { }
issue(account_name a, asset q): to(a), quantity(q) { }
account_name to;
asset quantity;
......@@ -134,6 +137,12 @@ namespace eosio {
act.send();
}
static void inline_issue(account_name to, token_type quantity)
{
action act(permission_level(code, N(active)), issue(to, asset(quantity)));
act.send();
}
static token_type get_total_supply() {
stats t( code, code );
auto ptr = t.find( symbol );
......
......@@ -510,7 +510,7 @@ static fc::variant producer_parameters_example(int n) {
("max_inline_depth", 4 + n)
("max_inline_action_size", 4096 + n)
("max_generated_transaction_size", 64*1024 + n)
("inflation_rate", 1050 + n)
("percent_of_max_inflation_rate", 50 + n)
("storage_reserve_ratio", 100 + n);
}
......@@ -672,5 +672,64 @@ BOOST_FIXTURE_TEST_CASE( vote_for_producer, eosio_system_tester ) try {
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try {
issue( "alice", "100000.0000 EOS", config::system_account_name );
fc::variant params = producer_parameters_example(50);
vector<char> key = fc::raw::pack(get_public_key(N(alice), "active"));
// 1 block produced
BOOST_REQUIRE_EQUAL(success(), push_action(N(alice), N(regproducer), mvo()
("producer", "alice")
("producer_key", key )
("prefs", params)
)
);
auto prod = get_producer_info( "alice" );
BOOST_REQUIRE_EQUAL(N(alice), prod["owner"].as_uint64());
BOOST_REQUIRE_EQUAL(0, prod["total_votes"].as_uint64());
REQUIRE_EQUAL_OBJECTS(params, prod["prefs"]);
BOOST_REQUIRE_EQUAL(string(key.begin(), key.end()), to_string(prod["packed_key"]));
issue("bob", "2000.0000 EOS", config::system_account_name);
// bob makes stake
// 1 block produced
BOOST_REQUIRE_EQUAL(success(), push_action(N(bob), N(delegatebw), mvo()
("from", "bob")
("receiver", "bob")
("stake_net", "11.0000 EOS")
("stake_cpu", "00.1111 EOS")
("stake_storage", "0.0000 EOS")
)
);
REQUIRE_EQUAL_OBJECTS(simple_voter("bob", "11.1111 EOS", last_block_time()), get_voter_info("bob"));
// bob votes for alice
// 1 block produced
BOOST_REQUIRE_EQUAL(success(), push_action(N(bob), N(voteproducer), mvo()
("voter", "bob")
("proxy", name(0).to_string())
("producers", vector<account_name>{ N(alice) })
)
);
produce_blocks(10);
prod = get_producer_info("alice");
BOOST_REQUIRE(prod["per_block_payments"].as_uint64() > 0);
// BOOST_REQUIRE_EQUAL(6 * 3925, prod["per_block_payments"].as_uint64());
BOOST_REQUIRE_EQUAL(success(), push_action(N(alice), N(claimrewards), mvo()
("owner", "alice")
)
);
prod = get_producer_info("alice");
BOOST_REQUIRE_EQUAL(0, prod["per_block_payments"].as_uint64());
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册