提交 19b51619 编写于 作者: D Daniel Larimer

progress

上级 02a09c67
......@@ -71,6 +71,10 @@ namespace eosiosystem {
EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(amount) )
};
/**
* These tables are designed to be constructed in the scope of the relevant user, this
* facilitates simpler API for per-user queries
*/
typedef eosio::multi_index< N(userres), user_resources> user_resources_table;
typedef eosio::multi_index< N(delband), delegated_bandwidth> del_bandwidth_table;
typedef eosio::multi_index< N(refunds), refund_request> refunds_table;
......@@ -93,15 +97,12 @@ namespace eosiosystem {
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)},
{ payer, N(eosio), quant, std::string("buy ram") } );
global_state_singleton gstate_table( _self, _self );
auto gstate = gstate_table.exists() ? gstate_table.get() : get_default_parameters();
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
const double unstaked_token_supply = system_token_supply - gstate.total_storage_stake.amount;
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount;
const double E = quant.amount;
const double R = unstaked_token_supply - E;
const double C = gstate.free_ram(); //free_ram;
const double C = _gstate.free_ram(); //free_ram;
const double F = .10; /// 10% reserve ratio pricing, assumes only 10% of tokens will ever want to stake for ram
const double ONE(1.0);
......@@ -111,10 +112,8 @@ namespace eosiosystem {
eosio_assert( bytes_out > 0, "must reserve a positive amount" );
gstate.total_storage_bytes_reserved += uint64_t(bytes_out);
gstate.total_storage_stake.amount += quant.amount;
gstate_table.set( gstate, _self );
_gstate.total_storage_bytes_reserved += uint64_t(bytes_out);
_gstate.total_storage_stake.amount += quant.amount;
user_resources_table userres( _self, receiver );
auto res_itr = userres.find( receiver );
......@@ -143,14 +142,11 @@ namespace eosiosystem {
eosio_assert( res_itr != userres.end(), "no resource row" );
eosio_assert( res_itr->storage_bytes >= bytes, "insufficient quota" );
global_state_singleton gstate_table( _self, _self );
auto gstate = gstate_table.exists() ? gstate_table.get() : get_default_parameters();
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
const double unstaked_token_supply = system_token_supply - gstate.total_storage_stake.amount;
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount;
const double R = unstaked_token_supply;
const double C = gstate.free_ram() + bytes;
const double C = _gstate.free_ram() + bytes;
const double F = .10;
const double T = bytes;
const double ONE(1.0);
......@@ -163,10 +159,8 @@ namespace eosiosystem {
int64_t tokens_out = int64_t(E);
eosio_assert( tokens_out > 0, "must free at least one token" );
gstate.total_storage_bytes_reserved -= bytes;
gstate.total_storage_stake.amount -= tokens_out;
gstate_table.set( gstate, _self );
_gstate.total_storage_bytes_reserved -= bytes;
_gstate.total_storage_stake.amount -= tokens_out;
userres.modify( res_itr, account, [&]( auto& res ) {
res.storage_bytes -= bytes;
......
......@@ -5,20 +5,35 @@
#include "producer_pay.cpp"
#include "voting.cpp"
system_contract::system_contract( account_name s )
:native(s),
_voters(_self,_self),
_producers(_self,_self),
_global(_self,_self)
{
_gstate = _global.exists() ? _global.get() : get_default_parameters();
}
system_contract::~system_contract() {
_global.set( _gstate, _self );
eosio_exit(0);
}
EOSIO_ABI( eosiosystem::system_contract,
(setparams)
// delegate_bandwith.cpp
(delegatebw)(undelegatebw)(refund)
(buyram)(sellram)
(regproxy)
// voting.cpp
(unregproxy)(regproducer)(unregprod)(voteproducer)
// producer_pay.cpp
(claimrewards)
// native.hpp
//XXX
(onblock)
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)
// defined in eosio.system.hpp
(nonce)
(setparams)
// delegate_bandwith.cpp
(delegatebw)(undelegatebw)(refund)
(buyram)(sellram)
(regproxy)
// voting.cpp
(unregproxy)(regproducer)(unregprod)(voteproducer)
// producer_pay.cpp
(claimrewards)
// native.hpp
//XXX
(onblock)
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)
// defined in eosio.system.hpp
(nonce)
)
......@@ -65,6 +65,40 @@ namespace eosiosystem {
(time_became_active)(last_produced_block_time) )
};
struct voter_info {
account_name owner = 0; /// the voter
account_name proxy = 0; /// the proxy set by the voter, if any
std::vector<account_name> producers; /// the producers approved by this voter if no proxy set
uint64_t staked;
/**
* Every time a vote is cast we must first "undo" the last vote weight, before casting the
* new vote weight. Vote weight is calculated as:
*
* stated.amount * 2 ^ ( weeks_since_launch/weeks_per_year)
*/
double last_vote_weight; /// the vote weight cast the last time the vote was updated
/**
* Total vote weight delegated to this voter.
*/
double proxied_vote_weight= 0; /// the total vote weight delegated to this voter as a proxy
bool is_proxy = 0; /// whether the voter is a proxy for others
uint32_t deferred_trx_id = 0; /// the ID of the 3-day delay deferred transaction
time last_unstake_time = 0; /// the time when the deferred_trx_id was sent
eosio::asset unstaking; /// the total unstaking (pending 3 day delay)
uint64_t primary_key()const { return owner; }
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE( voter_info, (owner)(proxy)(producers)(staked)(last_vote_weight)(proxied_vote_weight)(is_proxy)(deferred_trx_id)(last_unstake_time)(unstaking) )
};
typedef eosio::multi_index< N(voters), voter_info> voters_table;
typedef eosio::multi_index< N(producerinfo), producer_info,
indexed_by<N(prototalvote), const_mem_fun<producer_info, double, &producer_info::by_votes> >
> producers_table;
......@@ -76,8 +110,16 @@ namespace eosiosystem {
static constexpr uint64_t system_token_symbol = S(4,EOS);
class system_contract : public native {
private:
voters_table _voters;
producers_table _producers;
global_state_singleton _global;
eosio_global_state _gstate;
public:
using native::native;
system_contract( account_name s );
~system_contract();
// Actions:
void onblock( const block_id_type&, uint32_t timestamp_slot, account_name producer );
......
......@@ -30,26 +30,6 @@ namespace eosiosystem {
static constexpr uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year
static constexpr uint32_t blocks_per_producer = 12;
struct voter_info {
account_name owner = 0;
account_name proxy = 0;
time last_update = 0;
uint32_t is_proxy = 0;
eosio::asset staked; /// total staked across all delegations
eosio::asset unstaking;
eosio::asset unstake_per_week;
uint128_t proxied_votes = 0;
std::vector<account_name> producers;
uint32_t deferred_trx_id = 0;
time last_unstake_time = 0; //uint32
uint64_t primary_key()const { return owner; }
// explicit serialization macro is not necessary, used here only to improve compilation time
EOSLIB_SERIALIZE( voter_info, (owner)(proxy)(last_update)(is_proxy)(staked)(unstaking)(unstake_per_week)(proxied_votes)(producers)(deferred_trx_id)(last_unstake_time) )
};
typedef eosio::multi_index< N(voters), voter_info> voters_table;
/**
* This method will create a producer_config and producer_info object for 'producer'
......@@ -64,131 +44,73 @@ namespace eosiosystem {
//eosio::print("produce_key: ", producer_key.size(), ", sizeof(public_key): ", sizeof(public_key), "\n");
require_auth( producer );
producers_table producers_tbl( _self, _self );
auto prod = producers_tbl.find( producer );
auto prod = _producers.find( producer );
if ( prod != producers_tbl.end() ) {
if ( prod != _producers.end() ) {
if( producer_key != prod->producer_key ) {
producers_tbl.modify( prod, producer, [&]( producer_info& info ){
_producers.modify( prod, producer, [&]( producer_info& info ){
info.producer_key = producer_key;
});
});
}
} else {
producers_tbl.emplace( producer, [&]( producer_info& info ){
_producers.emplace( producer, [&]( producer_info& info ){
info.owner = producer;
info.total_votes = 0;
info.producer_key = producer_key;
});
});
}
}
void system_contract::unregprod( const account_name producer ) {
require_auth( producer );
producers_table producers_tbl( _self, _self );
auto prod = producers_tbl.find( producer );
auto prod = _producers.find( producer );
eosio_assert( prod != producers_tbl.end(), "producer not found" );
producers_tbl.modify( prod, 0, [&]( producer_info& info ){
info.producer_key = public_key();
});
_producers.modify( prod, 0, [&]( producer_info& info ){
info.producer_key = public_key();
});
}
void system_contract::adjust_voting_power( account_name acnt, int64_t delta ) {
voters_table voters_tbl( _self, _self );
auto voter = voters_tbl.find( acnt );
if( voter == voters_tbl.end() ) {
voter = voters_tbl.emplace( acnt, [&]( voter_info& a ) {
a.owner = acnt;
a.last_update = now();
a.staked.amount = delta;
eosio_assert( a.staked.amount >= 0, "underflow" );
});
} else {
voters_tbl.modify( voter, 0, [&]( auto& av ) {
av.last_update = now();
av.staked.amount += delta;
eosio_assert( av.staked.amount >= 0, "underflow" );
});
}
auto voter = _voters.find( acnt );
const std::vector<account_name>* producers = nullptr;
if ( voter->proxy ) {
/* TODO: disabled until we can switch proxied votes to double
auto proxy = voters_tbl.find( voter->proxy );
eosio_assert( proxy != voters_tbl.end(), "selected proxy not found" ); //data corruption
voters_tbl.modify( proxy, 0, [&](voter_info& a) { a.proxied_votes += delta; } );
if ( proxy->is_proxy ) { //only if proxy is still active. if proxy has been unregistered, we update proxied_votes, but don't propagate to producers
producers = &proxy->producers;
}
*/
if( voter == _voters.end() ) {
voter = _voters.emplace( acnt, [&]( voter_info& a ) {
a.owner = acnt;
a.staked.amount = delta;
});
}
} else {
producers = &voter->producers;
}
auto weight = int64_t(now() / (seconds_per_day * 7)) / double( 52 );
double new_vote_weight = double(voter->staked.amount + delta) * std::pow(2,weight) + voter->proxied_vote_weight;
if ( producers ) {
producers_table producers_tbl( _self, _self );
for( auto p : *producers ) {
auto prod = producers_tbl.find( p );
eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption
producers_tbl.modify( prod, 0, [&]( auto& v ) {
v.total_votes += delta;
});
}
}
}
auto delta_vote_weight = new_vote_weight - voter->last_vote_weight;
/*
void system_contract::decrease_voting_power( account_name acnt, const eosio::asset& amount ) {
require_auth( acnt );
voters_table voters_tbl( _self, _self );
auto voter = voters_tbl.find( acnt );
eosio_assert( voter != voters_tbl.end(), "stake not found" );
_voters.modify( voter, 0, [&]( auto& av ) {
av.staked.amount += delta;
av.last_vote_weight = new_vote_weight;
eosio_assert( av.staked.amount >= 0, "underflow" );
});
if ( 0 < amount.amount ) {
eosio_assert( amount <= voter->staked, "cannot unstake more than total stake amount" );
voters_tbl.modify( voter, 0, [&](voter_info& a) {
a.staked -= amount;
a.last_update = now();
});
const std::vector<account_name>* producers = nullptr;
if ( voter->proxy ) {
auto proxy = voters_tbl.find( voter->proxy );
eosio_assert( proxy != voters_tbl.end(), "selected proxy not found" );
const std::vector<account_name>* producers = nullptr;
if ( voter->proxy ) {
auto proxy = voters_tbl.find( voter->proxy );
voters_tbl.modify( proxy, 0, [&](voter_info& a) { a.proxied_votes -= uint64_t(amount.amount); } );
if ( proxy->is_proxy ) { //only if proxy is still active. if proxy has been unregistered, we update proxied_votes, but don't propagate to producers
producers = &proxy->producers;
}
} else {
producers = &voter->producers;
}
_voters.modify( proxy, 0, [&](voter_info& a) {
a.proxied_vote_weight += delta_vote_weight;
} );
if ( producers ) {
producers_table producers_tbl( _self, _self );
for( auto p : *producers ) {
auto prod = producers_tbl.find( p );
eosio_assert( prod != producers_tbl.end(), "never existed producer" ); //data corruption
producers_tbl.modify( prod, 0, [&]( auto& v ) {
v.total_votes -= uint64_t(amount.amount);
});
}
}
} else {
if (voter->deferred_trx_id) {
//XXX cancel_deferred_transaction(voter->deferred_trx_id);
}
voters_tbl.modify( voter, 0, [&](voter_info& a) {
a.staked += a.unstaking;
a.unstaking.amount = 0;
a.unstake_per_week.amount = 0;
a.deferred_trx_id = 0;
a.last_update = now();
for( auto p : voter->producers ) {
auto prod = _producers.find( p );
_producers.modify( prod, 0, [&]( auto& pro ) {
pro.total_votes += delta_vote_weight;
});
}
}
}
*/
eosio_global_state system_contract::get_default_parameters() {
eosio_global_state dp;
......@@ -196,6 +118,7 @@ namespace eosiosystem {
return dp;
}
eosio::asset system_contract::payment_per_block(uint32_t percent_of_max_inflation_rate) {
const eosio::asset token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name());
const double annual_rate = double(max_inflation_rate * percent_of_max_inflation_rate) / double(10000);
......@@ -205,8 +128,7 @@ namespace eosiosystem {
}
void system_contract::update_elected_producers(time cycle_time) {
producers_table producers_tbl( _self, _self );
auto idx = producers_tbl.template get_index<N(prototalvote)>();
auto idx = _producers.get_index<N(prototalvote)>();
eosio::producer_schedule schedule;
schedule.producers.reserve(21);
......@@ -227,29 +149,25 @@ namespace eosiosystem {
bytes packed_schedule = pack(schedule);
set_active_producers( packed_schedule.data(), packed_schedule.size() );
global_state_singleton gs( _self, _self );
auto parameters = gs.exists() ? gs.get() : get_default_parameters();
// not voted on
parameters.first_block_time_in_cycle = cycle_time;
_gstate.first_block_time_in_cycle = cycle_time;
// derived parameters
auto half_of_percentage = parameters.percent_of_max_inflation_rate / 2;
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 = blocks_per_producer * schedule.producers.size();
if ( parameters.max_storage_size < parameters.total_storage_bytes_reserved ) {
parameters.max_storage_size = parameters.total_storage_bytes_reserved;
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();
if (_gstate.max_storage_size <_gstate.total_storage_bytes_reserved ) {
_gstate.max_storage_size =_gstate.total_storage_bytes_reserved;
}
auto issue_quantity = parameters.blocks_per_cycle * (parameters.payment_per_block + parameters.payment_to_eos_bucket);
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")} );
set_blockchain_parameters( parameters );
gs.set( parameters, _self );
set_blockchain_parameters( _gstate );
}
/**
......@@ -259,12 +177,13 @@ namespace eosiosystem {
* @pre voter must authorize this action
* @pre voter must have previously staked some EOS for voting
*/
void system_contract::voteproducer( const account_name voter, const account_name proxy, const std::vector<account_name>& producers ) {
require_auth( voter );
void system_contract::voteproducer( const account_name voter_name, const account_name proxy, const std::vector<account_name>& producers ) {
require_auth( voter_name );
//validate input
if ( proxy ) {
eosio_assert( producers.size() == 0, "cannot vote for producers and proxy at same time" );
eosio_assert( voter_name != proxy, "cannot proxy to self" );
require_recipient( proxy );
} else {
eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" );
......@@ -273,8 +192,56 @@ namespace eosiosystem {
}
}
voters_table voters_tbl( _self, _self );
auto voter_it = voters_tbl.find( voter );
auto voter = _voters.find(voter_name);
eosio_assert( voter != _voters.end(), "user must stake before they can vote" ); /// staking creates voter object
auto weight = int64_t(now() / (seconds_per_day * 7)) / double( 52 );
double new_vote_weight = double(voter->staked) * std::pow(2,weight) + voter->proxied_vote_weight;
flat_map<account_name, double> producer_deltas;
for( const auto& p : voter->producers ) {
producer_deltas[p] -= voter->last_vote_weight;
}
for( const auto& p : producers ) {
producer_deltas[p] += voter->last_vote_weight;
}
if( voter->proxy ) {
if( voter->proxy != proxy ) {
} else {
}
} else {
}
_voters.modify( voter, 0, [&]( auto& av ) {
av.last_vote_weight = new_vote_weight;
av.producers = producers;
av.proxy = proxy;
});
auto voter_it = _voters.find( voter );
/// remove all votes from existing producers or proxy
adjust_voting_power( voter, -voter_it->staked.amount );
/// update producer list
/// add all votes to new producers or proxy
adjust_voting_power( voter, voter_it->staked.amount );
eosio_assert( 0 <= voter_it->staked.amount, "negative stake" );
eosio_assert( voter_it != voters_tbl.end() && ( 0 < voter_it->staked.amount || ( voter_it->is_proxy && 0 < voter_it->proxied_votes ) ), "no stake to vote" );
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册