diff --git a/contracts/eosio.system_bak/CMakeLists.txt b/contracts/eosio.system_bak/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb4ff749f77fe230351554f82615434673f1114b --- /dev/null +++ b/contracts/eosio.system_bak/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB ABI_FILES "*.abi") +configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) + +add_wast_executable(TARGET eosio.system + INCLUDE_FOLDERS ${STANDARD_INCLUDE_FOLDERS} + LIBRARIES libc++ libc eosiolib eosio.token + DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/contracts/eosio.system_bak/README.md b/contracts/eosio.system_bak/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9e5c3160069b8b9b967cfd9c666480433e2bf853 --- /dev/null +++ b/contracts/eosio.system_bak/README.md @@ -0,0 +1,84 @@ +eosio.system +---------- + +This contract enables users to stake tokens, and then configure and vote on producers and worker proposals. + +Users can also proxy their voting influence to other users. + +The state of this contract is read to determine the 21 active block producers. + +Actions: +The naming convention is codeaccount::actionname followed by a list of paramters. + +Indicates that a particular account wishes to become a producer +## eosio.system::cfgproducer account config + - **account** the producer account to update + - updates the configuration settings for a particular producer, these + + Storage changes are billed to 'account' + +## eosio.system::okproducer account producer vote + - **account** the account which is doing the voting + - **producer** the producer which is being voted for (or unvoted for) + - **vote** true if the producer should be voted for, false if not + + Each account has a maximum number of votes it can maintain. Storage changes will be billed to 'account' + +## eosio.system::setproxy account proxy + - **account** the account which is updating it's proxy + - **proxy** the account which will have the power to vote account's stake + + All current votes are removed and a new proxy link is created. The votes for every producer the proxy + has voted for are updated immediately. + + Storage changes will be billed to 'account' + +## eosio.system::unstake account quantity + - **account** - the account which is requesting their balance be unstaked + - **quantity** - the quantity which will be unstaked, unstaked tokens lose voting influence immediately + + - in order to unstake tokens, an account must request them. The user will receive them over + time via weekly withdraws. The length of time will be configured by the median time as set by + the active producers. + + - If this is called while in the process of unstaking, the currently pending unstake is canceled as if + quantity were 0, then it is applied as if a new unstake request was made. + + - all producers this 'from' has voted for will have their votes updated immediately. + + - bandwidth and storage for the deferred transaction will be billed to 'from' + +## eosio.system::withdraw account + - this action can only be triggered by eosio.system via a deferred transaction generated by unstake + - this will generate an inline eosio.token::transfer call from=eosio.system to=account and amount equal to the next withdraw increment + - this will generate another deferred withdraw to continue the process if there are still withdraws to be made + + +## eosio.system::transfer from to amount memo + - decrements balance of from if amount <= balance + - increments balance of to by amount + - memo is ignored + +## eosio.system::stakevote account amount + - the primary currency of eosio is controlled by the token contract which enables users to transfer + balances from one user to another. The receiver is notified on incoming balances and the vote contract + will stake the tokens on receipt. + + - all producers this 'from' has voted for will have their votes updated immediately. + + +## eosio.system::onblock account blocktime blocknum + - this special action is triggered when a block is applied by the given producer and cannot be generated from + any other source. It is used to pay producers and calculate missed blocks of other producers. + + - producer pay is deposited into the producer's stake balance and can be withdrawn over time. + + - if blocknum is the start of a new round this may update the active producer config from the producer votes. + +## eosio.system::freeze producer accounts true|false + - requires permission of the @producers account + - if an account is frozen, all authorizations of that account are rejected and the code for that account will not be run + +## eosio.system::paystandby producer + - every block some amount of tokens is paid + - at most once per day a producer may claim a percentage of the standby pay equal to their totalvotes / allvotes diff --git a/contracts/eosio.system_bak/delegate_bandwidth.cpp b/contracts/eosio.system_bak/delegate_bandwidth.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d37ee0554ea4dd9f83c867be6c1b15e9779fcdea --- /dev/null +++ b/contracts/eosio.system_bak/delegate_bandwidth.cpp @@ -0,0 +1,426 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include "eosio.system.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include +#include + +namespace eosiosystem { + using eosio::asset; + using eosio::indexed_by; + using eosio::const_mem_fun; + using eosio::bytes; + using eosio::print; + using eosio::permission_level; + using std::map; + using std::pair; + + static constexpr time refund_delay = 3*24*3600; + static constexpr time refund_expiration_time = 3600; + + struct user_resources { + account_name owner; + asset net_weight; + asset cpu_weight; + int64_t ram_bytes = 0; + + uint64_t primary_key()const { return owner; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( user_resources, (owner)(net_weight)(cpu_weight)(ram_bytes) ) + }; + + + /** + * Every user 'from' has a scope/table that uses every receipient 'to' as the primary key. + */ + struct delegated_bandwidth { + account_name from; + account_name to; + asset net_weight; + asset cpu_weight; + + uint64_t primary_key()const { return to; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( delegated_bandwidth, (from)(to)(net_weight)(cpu_weight) ) + + }; + + struct refund_request { + account_name owner; + time request_time; + eosio::asset net_amount; + eosio::asset cpu_amount; + + uint64_t primary_key()const { return owner; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_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; + + + + /** + * This action will buy an exact amount of ram and bill the payer the current market price. + */ + void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) { + auto itr = _rammarket.find(S(4,RAMCORE)); + auto tmp = *itr; + auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL ); + + buyram( payer, receiver, eosout ); + } + + + /** + * When buying ram the payer irreversiblly transfers quant to system contract and only + * the receiver may reclaim the tokens via the sellram action. The receiver pays for the + * storage of all database records associated with this action. + * + * RAM is a scarce resource whose supply is defined by global properties max_ram_size. RAM is + * priced using the bancor algorithm such that price-per-byte with a constant reserve ratio of 100:1. + */ + void system_contract::buyram( account_name payer, account_name receiver, asset quant ) + { + require_auth( payer ); + eosio_assert( quant.amount > 0, "must purchase a positive amount" ); + + auto fee = quant; + fee.amount = ( fee.amount + 199 ) / 200; /// .5% fee (round up) + // fee.amount cannot be 0 since that is only possible if quant.amount is 0 which is not allowed by the assert above. + // If quant.amount == 1, then fee.amount == 1, + // otherwise if quant.amount > 1, then 0 < fee.amount < quant.amount. + auto quant_after_fee = quant; + quant_after_fee.amount -= fee.amount; + // quant_after_fee.amount should be > 0 if quant.amount > 1. + // If quant.amount == 1, then quant_after_fee.amount == 0 and the next inline transfer will fail causing the buyram action to fail. + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)}, + { payer, N(eosio.ram), quant_after_fee, std::string("buy ram") } ); + + if( fee.amount > 0 ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)}, + { payer, N(eosio.ramfee), fee, std::string("ram fee") } ); + } + + int64_t bytes_out; + + const auto& market = _rammarket.get(S(4,RAMCORE), "ram market does not exist"); + _rammarket.modify( market, 0, [&]( auto& es ) { + bytes_out = es.convert( quant_after_fee, S(0,RAM) ).amount; + }); + + eosio_assert( bytes_out > 0, "must reserve a positive amount" ); + + _gstate.total_ram_bytes_reserved += uint64_t(bytes_out); + _gstate.total_ram_stake += quant_after_fee.amount; + + user_resources_table userres( _self, receiver ); + auto res_itr = userres.find( receiver ); + if( res_itr == userres.end() ) { + res_itr = userres.emplace( receiver, [&]( auto& res ) { + res.owner = receiver; + res.ram_bytes = bytes_out; + }); + } else { + userres.modify( res_itr, receiver, [&]( auto& res ) { + res.ram_bytes += bytes_out; + }); + } + set_resource_limits( res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); + } + + + /** + * The system contract now buys and sells RAM allocations at prevailing market prices. + * This may result in traders buying RAM today in anticipation of potential shortages + * tomorrow. Overall this will result in the market balancing the supply and demand + * for RAM over time. + */ + void system_contract::sellram( account_name account, int64_t bytes ) { + require_auth( account ); + eosio_assert( bytes > 0, "cannot sell negative byte" ); + + user_resources_table userres( _self, account ); + auto res_itr = userres.find( account ); + eosio_assert( res_itr != userres.end(), "no resource row" ); + eosio_assert( res_itr->ram_bytes >= bytes, "insufficient quota" ); + + asset tokens_out; + auto itr = _rammarket.find(S(4,RAMCORE)); + _rammarket.modify( itr, 0, [&]( auto& es ) { + /// the cast to int64_t of bytes is safe because we certify bytes is <= quota which is limited by prior purchases + tokens_out = es.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL); + }); + + eosio_assert( tokens_out.amount > 1, "token amount received from selling ram is too low" ); + + _gstate.total_ram_bytes_reserved -= static_cast(bytes); // bytes > 0 is asserted above + _gstate.total_ram_stake -= tokens_out.amount; + + //// this shouldn't happen, but just in case it does we should prevent it + eosio_assert( _gstate.total_ram_stake >= 0, "error, attempt to unstake more tokens than previously staked" ); + + userres.modify( res_itr, account, [&]( auto& res ) { + res.ram_bytes -= bytes; + }); + set_resource_limits( res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.ram),N(active)}, + { N(eosio.ram), account, asset(tokens_out), std::string("sell ram") } ); + + auto fee = ( tokens_out.amount + 199 ) / 200; /// .5% fee (round up) + // since tokens_out.amount was asserted to be at least 2 earlier, fee.amount < tokens_out.amount + + if( fee > 0 ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {account,N(active)}, + { account, N(eosio.ramfee), asset(fee), std::string("sell ram fee") } ); + } + } + + void validate_b1_vesting( int64_t stake ) { + const int64_t base_time = 1527811200; /// 2018-06-01 + const int64_t max_claimable = 100'000'000'0000ll; + const int64_t claimable = int64_t(max_claimable * double(now()-base_time) / (10*seconds_per_year) ); + + eosio_assert( max_claimable - claimable <= stake, "b1 can only claim their tokens over 10 years" ); + } + + void system_contract::changebw( account_name from, account_name receiver, + const asset stake_net_delta, const asset stake_cpu_delta, bool transfer ) + { + require_auth( from ); + eosio_assert( stake_net_delta != asset(0) || stake_cpu_delta != asset(0), "should stake non-zero amount" ); + eosio_assert( std::abs( (stake_net_delta + stake_cpu_delta).amount ) + >= std::max( std::abs( stake_net_delta.amount ), std::abs( stake_cpu_delta.amount ) ), + "net and cpu deltas cannot be opposite signs" ); + + account_name source_stake_from = from; + if ( transfer ) { + from = receiver; + } + + // update stake delegated from "from" to "receiver" + { + del_bandwidth_table del_tbl( _self, from); + auto itr = del_tbl.find( receiver ); + if( itr == del_tbl.end() ) { + itr = del_tbl.emplace( from, [&]( auto& dbo ){ + dbo.from = from; + dbo.to = receiver; + dbo.net_weight = stake_net_delta; + dbo.cpu_weight = stake_cpu_delta; + }); + } + else { + del_tbl.modify( itr, 0, [&]( auto& dbo ){ + dbo.net_weight += stake_net_delta; + dbo.cpu_weight += stake_cpu_delta; + }); + } + eosio_assert( asset(0) <= itr->net_weight, "insufficient staked net bandwidth" ); + eosio_assert( asset(0) <= itr->cpu_weight, "insufficient staked cpu bandwidth" ); + if ( itr->net_weight == asset(0) && itr->cpu_weight == asset(0) ) { + del_tbl.erase( itr ); + } + } // itr can be invalid, should go out of scope + + // update totals of "receiver" + { + user_resources_table totals_tbl( _self, receiver ); + auto tot_itr = totals_tbl.find( receiver ); + if( tot_itr == totals_tbl.end() ) { + tot_itr = totals_tbl.emplace( from, [&]( auto& tot ) { + tot.owner = receiver; + tot.net_weight = stake_net_delta; + tot.cpu_weight = stake_cpu_delta; + }); + } else { + totals_tbl.modify( tot_itr, from == receiver ? from : 0, [&]( auto& tot ) { + tot.net_weight += stake_net_delta; + tot.cpu_weight += stake_cpu_delta; + }); + } + eosio_assert( asset(0) <= tot_itr->net_weight, "insufficient staked total net bandwidth" ); + eosio_assert( asset(0) <= tot_itr->cpu_weight, "insufficient staked total cpu bandwidth" ); + + set_resource_limits( receiver, tot_itr->ram_bytes, tot_itr->net_weight.amount, tot_itr->cpu_weight.amount ); + + if ( tot_itr->net_weight == asset(0) && tot_itr->cpu_weight == asset(0) && tot_itr->ram_bytes == 0 ) { + totals_tbl.erase( tot_itr ); + } + } // tot_itr can be invalid, should go out of scope + + // create refund or update from existing refund + if ( N(eosio.stake) != source_stake_from ) { //for eosio both transfer and refund make no sense + refunds_table refunds_tbl( _self, from ); + auto req = refunds_tbl.find( from ); + + //create/update/delete refund + auto net_balance = stake_net_delta; + auto cpu_balance = stake_cpu_delta; + bool need_deferred_trx = false; + + + // net and cpu are same sign by assertions in delegatebw and undelegatebw + // redundant assertion also at start of changebw to protect against misuse of changebw + bool is_undelegating = (net_balance.amount + cpu_balance.amount ) < 0; + bool is_delegating_to_self = (!transfer && from == receiver); + + if( is_delegating_to_self || is_undelegating ) { + if ( req != refunds_tbl.end() ) { //need to update refund + refunds_tbl.modify( req, 0, [&]( refund_request& r ) { + if ( net_balance < asset(0) || cpu_balance < asset(0) ) { + r.request_time = now(); + } + r.net_amount -= net_balance; + if ( r.net_amount < asset(0) ) { + net_balance = -r.net_amount; + r.net_amount = asset(0); + } else { + net_balance = asset(0); + } + r.cpu_amount -= cpu_balance; + if ( r.cpu_amount < asset(0) ){ + cpu_balance = -r.cpu_amount; + r.cpu_amount = asset(0); + } else { + cpu_balance = asset(0); + } + }); + + eosio_assert( asset(0) <= req->net_amount, "negative net refund amount" ); //should never happen + eosio_assert( asset(0) <= req->cpu_amount, "negative cpu refund amount" ); //should never happen + + if ( req->net_amount == asset(0) && req->cpu_amount == asset(0) ) { + refunds_tbl.erase( req ); + need_deferred_trx = false; + } else { + need_deferred_trx = true; + } + + } else if ( net_balance < asset(0) || cpu_balance < asset(0) ) { //need to create refund + refunds_tbl.emplace( from, [&]( refund_request& r ) { + r.owner = from; + if ( net_balance < asset(0) ) { + r.net_amount = -net_balance; + net_balance = asset(0); + } // else r.net_amount = 0 by default constructor + if ( cpu_balance < asset(0) ) { + r.cpu_amount = -cpu_balance; + cpu_balance = asset(0); + } // else r.cpu_amount = 0 by default constructor + r.request_time = now(); + }); + need_deferred_trx = true; + } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl + } /// end if is_delegating_to_self || is_undelegating + + if ( need_deferred_trx ) { + eosio::transaction out; + out.actions.emplace_back( permission_level{ from, N(active) }, _self, N(refund), from ); + out.delay_sec = refund_delay; + cancel_deferred( from ); // TODO: Remove this line when replacing deferred trxs is fixed + out.send( from, from, true ); + } else { + cancel_deferred( from ); + } + + auto transfer_amount = net_balance + cpu_balance; + if ( asset(0) < transfer_amount ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {source_stake_from, N(active)}, + { source_stake_from, N(eosio.stake), asset(transfer_amount), std::string("stake bandwidth") } ); + } + } + + // update voting power + { + asset total_update = stake_net_delta + stake_cpu_delta; + auto from_voter = _voters.find(from); + if( from_voter == _voters.end() ) { + from_voter = _voters.emplace( from, [&]( auto& v ) { + v.owner = from; + v.staked = total_update.amount; + }); + } else { + _voters.modify( from_voter, 0, [&]( auto& v ) { + v.staked += total_update.amount; + }); + } + eosio_assert( 0 <= from_voter->staked, "stake for voting cannot be negative"); + if( from == N(b1) ) { + validate_b1_vesting( from_voter->staked ); + } + + if( from_voter->producers.size() || from_voter->proxy ) { + update_votes( from, from_voter->proxy, from_voter->producers, false ); + } + } + } + + void system_contract::delegatebw( account_name from, account_name receiver, + asset stake_net_quantity, + asset stake_cpu_quantity, bool transfer ) + { + eosio_assert( stake_cpu_quantity >= asset(0), "must stake a positive amount" ); + eosio_assert( stake_net_quantity >= asset(0), "must stake a positive amount" ); + eosio_assert( stake_net_quantity + stake_cpu_quantity > asset(0), "must stake a positive amount" ); + eosio_assert( !transfer || from != receiver, "cannot use transfer flag if delegating to self" ); + + changebw( from, receiver, stake_net_quantity, stake_cpu_quantity, transfer); + } // delegatebw + + void system_contract::undelegatebw( account_name from, account_name receiver, + asset unstake_net_quantity, asset unstake_cpu_quantity ) + { + eosio_assert( asset() <= unstake_cpu_quantity, "must unstake a positive amount" ); + eosio_assert( asset() <= unstake_net_quantity, "must unstake a positive amount" ); + eosio_assert( asset() < unstake_cpu_quantity + unstake_net_quantity, "must unstake a positive amount" ); + eosio_assert( _gstate.total_activated_stake >= min_activated_stake, + "cannot undelegate bandwidth until the chain is activated (at least 15% of all tokens participate in voting)" ); + + changebw( from, receiver, -unstake_net_quantity, -unstake_cpu_quantity, false); + } // undelegatebw + + + void system_contract::refund( const account_name owner ) { + require_auth( owner ); + + refunds_table refunds_tbl( _self, owner ); + auto req = refunds_tbl.find( owner ); + eosio_assert( req != refunds_tbl.end(), "refund request not found" ); + eosio_assert( req->request_time + refund_delay <= now(), "refund is not available yet" ); + // Until now() becomes NOW, the fact that now() is the timestamp of the previous block could in theory + // allow people to get their tokens earlier than the 3 day delay if the unstake happened immediately after many + // consecutive missed blocks. + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.stake),N(active)}, + { N(eosio.stake), req->owner, req->net_amount + req->cpu_amount, std::string("unstake") } ); + + refunds_tbl.erase( req ); + } + + +} //namespace eosiosystem diff --git a/contracts/eosio.system_bak/eosio.system.abi b/contracts/eosio.system_bak/eosio.system.abi new file mode 100644 index 0000000000000000000000000000000000000000..bc0017f981c24eb4fc63e44f39bce6b488cb2a2e --- /dev/null +++ b/contracts/eosio.system_bak/eosio.system.abi @@ -0,0 +1,697 @@ +{ + "version": "eosio::abi/1.0", + "types": [{ + "new_type_name": "account_name", + "type": "name" + },{ + "new_type_name": "permission_name", + "type": "name" + },{ + "new_type_name": "action_name", + "type": "name" + },{ + "new_type_name": "transaction_id_type", + "type": "checksum256" + },{ + "new_type_name": "weight_type", + "type": "uint16" + }], + "____comment": "eosio.bios structs: set_account_limits, setpriv, set_global_limits, producer_key, set_producers, require_auth are provided so abi available for deserialization in future.", + "structs": [{ + "name": "permission_level", + "base": "", + "fields": [ + {"name":"actor", "type":"account_name"}, + {"name":"permission", "type":"permission_name"} + ] + },{ + "name": "key_weight", + "base": "", + "fields": [ + {"name":"key", "type":"public_key"}, + {"name":"weight", "type":"weight_type"} + ] + },{ + "name": "prod_meta", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"total_votes", "type":"float64"}, + {"name":"producer_key", "type":"public_key"}, + {"name":"all_stake", "type":"int64"}, + {"name":"is_active", "type":"bool"}, + {"name":"url", "type":"string"}, + {"name":"location", "type":"uint16"} + ] + },{ + "name": "bidname", + "base": "", + "fields": [ + {"name":"bidder", "type":"account_name"}, + {"name":"newname", "type":"account_name"}, + {"name":"bid", "type":"asset"} + ] + },{ + "name": "permission_level_weight", + "base": "", + "fields": [ + {"name":"permission", "type":"permission_level"}, + {"name":"weight", "type":"weight_type"} + ] + },{ + "name": "wait_weight", + "base": "", + "fields": [ + {"name":"wait_sec", "type":"uint32"}, + {"name":"weight", "type":"weight_type"} + ] + },{ + "name": "authority", + "base": "", + "fields": [ + {"name":"threshold", "type":"uint32"}, + {"name":"keys", "type":"key_weight[]"}, + {"name":"accounts", "type":"permission_level_weight[]"}, + {"name":"waits", "type":"wait_weight[]"} + ] + },{ + "name": "newaccount", + "base": "", + "fields": [ + {"name":"creator", "type":"account_name"}, + {"name":"name", "type":"account_name"}, + {"name":"owner", "type":"authority"}, + {"name":"active", "type":"authority"} + ] + },{ + "name": "setcode", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"vmtype", "type":"uint8"}, + {"name":"vmversion", "type":"uint8"}, + {"name":"code", "type":"bytes"} + ] + },{ + "name": "setabi", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"abi", "type":"bytes"} + ] + },{ + "name": "updateauth", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"permission", "type":"permission_name"}, + {"name":"parent", "type":"permission_name"}, + {"name":"auth", "type":"authority"} + ] + },{ + "name": "deleteauth", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"permission", "type":"permission_name"} + ] + },{ + "name": "linkauth", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"code", "type":"account_name"}, + {"name":"type", "type":"action_name"}, + {"name":"requirement", "type":"permission_name"} + ] + },{ + "name": "unlinkauth", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"code", "type":"account_name"}, + {"name":"type", "type":"action_name"} + ] + },{ + "name": "canceldelay", + "base": "", + "fields": [ + {"name":"canceling_auth", "type":"permission_level"}, + {"name":"trx_id", "type":"transaction_id_type"} + ] + },{ + "name": "onerror", + "base": "", + "fields": [ + {"name":"sender_id", "type":"uint128"}, + {"name":"sent_trx", "type":"bytes"} + ] + },{ + "name": "buyrambytes", + "base": "", + "fields": [ + {"name":"payer", "type":"account_name"}, + {"name":"receiver", "type":"account_name"}, + {"name":"bytes", "type":"uint32"} + ] + },{ + "name": "sellram", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"bytes", "type":"uint64"} + ] + },{ + "name": "buyram", + "base": "", + "fields": [ + {"name":"payer", "type":"account_name"}, + {"name":"receiver", "type":"account_name"}, + {"name":"quant", "type":"asset"} + ] + },{ + "name": "delegatebw", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"}, + {"name":"receiver", "type":"account_name"}, + {"name":"stake_net_quantity", "type":"asset"}, + {"name":"stake_cpu_quantity", "type":"asset"}, + {"name":"transfer", "type":"bool"} + ] + },{ + "name": "undelegatebw", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"}, + {"name":"receiver", "type":"account_name"}, + {"name":"unstake_net_quantity", "type":"asset"}, + {"name":"unstake_cpu_quantity", "type":"asset"} + ] + },{ + "name": "refund", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"} + ] + },{ + "name": "delegated_bandwidth", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"}, + {"name":"to", "type":"account_name"}, + {"name":"net_weight", "type":"asset"}, + {"name":"cpu_weight", "type":"asset"} + ] + },{ + "name": "user_resources", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"net_weight", "type":"asset"}, + {"name":"cpu_weight", "type":"asset"}, + {"name":"ram_bytes", "type":"uint64"} + ] + },{ + "name": "total_resources", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"net_weight", "type":"asset"}, + {"name":"cpu_weight", "type":"asset"}, + {"name":"ram_bytes", "type":"uint64"} + ] + },{ + "name": "refund_request", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"request_time", "type":"time_point_sec"}, + {"name":"net_amount", "type":"asset"}, + {"name":"cpu_amount", "type":"asset"} + ] + },{ + "name": "blockchain_parameters", + "base": "", + "fields": [ + + {"name":"max_block_net_usage", "type":"uint64"}, + {"name":"target_block_net_usage_pct", "type":"uint32"}, + {"name":"max_transaction_net_usage", "type":"uint32"}, + {"name":"base_per_transaction_net_usage", "type":"uint32"}, + {"name":"net_usage_leeway", "type":"uint32"}, + {"name":"context_free_discount_net_usage_num", "type":"uint32"}, + {"name":"context_free_discount_net_usage_den", "type":"uint32"}, + {"name":"max_block_cpu_usage", "type":"uint32"}, + {"name":"target_block_cpu_usage_pct", "type":"uint32"}, + {"name":"max_transaction_cpu_usage", "type":"uint32"}, + {"name":"min_transaction_cpu_usage", "type":"uint32"}, + {"name":"max_transaction_lifetime", "type":"uint32"}, + {"name":"deferred_trx_expiration_window", "type":"uint32"}, + {"name":"max_transaction_delay", "type":"uint32"}, + {"name":"max_inline_action_size", "type":"uint32"}, + {"name":"max_inline_action_depth", "type":"uint16"}, + {"name":"max_authority_depth", "type":"uint16"} + + ] + },{ + "name": "eosio_global_state", + "base": "blockchain_parameters", + "fields": [ + {"name":"max_ram_size", "type":"uint64"}, + {"name":"total_ram_bytes_reserved", "type":"uint64"}, + {"name":"total_ram_stake", "type":"int64"}, + {"name":"last_producer_schedule_update", "type":"block_timestamp_type"}, + {"name":"last_pervote_bucket_fill", "type":"uint64"}, + {"name":"pervote_bucket", "type":"int64"}, + {"name":"perblock_bucket", "type":"int64"}, + {"name":"total_unpaid_blocks", "type":"uint32"}, + {"name":"total_activated_stake", "type":"int64"}, + {"name":"thresh_activated_stake_time", "type":"uint64"}, + {"name":"last_producer_schedule_size", "type":"uint16"}, + {"name":"total_producer_vote_weight", "type":"float64"}, + {"name":"last_name_close", "type":"block_timestamp_type"} + ] + },{ + "name": "eosio_global_state2", + "base": "", + "fields": [ + {"name":"perbase_bucket", "type":"int64"}, + {"name":"total_unpaid_base_cnt", "type":"uint32"}, + {"name":"last_claim_time", "type":"uint64"} + ] + },{ + "name": "eosio_global_count", + "base": "", + "fields": [ + {"name":"total_accounts", "type":"uint64"} + ] + },{ + "name": "producer_info", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"total_votes", "type":"float64"}, + {"name":"producer_key", "type":"public_key"}, + {"name":"is_active", "type":"bool"}, + {"name":"url", "type":"string"}, + {"name":"unpaid_blocks", "type":"uint32"}, + {"name":"last_claim_time", "type":"uint64"}, + {"name":"location", "type":"uint16"} + ] + },{ + "name": "producer_info_ext", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"seq_num", "type":"uint16"}, + {"name":"out_votes", "type":"int64"}, + {"name":"unpaid_base_cnt", "type":"uint32"} + ] + },{ + "name": "producers_seq", + "base": "", + "fields": [ + {"name":"seq_num", "type":"uint16"}, + {"name":"is_org", "type":"bool"}, + {"name":"prods_l1", "type":"prod_meta"}, + {"name":"prods_l2", "type":"prod_meta[]"}, + {"name":"prods_l3", "type":"prod_meta[]"}, + {"name":"prods_all", "type":"prod_meta[]"}, + + + ] + },{ + "name": "regproducer", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"}, + {"name":"producer_key", "type":"public_key"}, + {"name":"url", "type":"string"}, + {"name":"location", "type":"uint16"} + ] + },{ + "name": "unregprod", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"} + ] + },{ + "name": "clsprods2", + "base": "", + "fields": [] + },{ + "name": "seqproducer", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"}, + {"name":"seq", "type":"uint16"}, + {"name":"level", "type":"uint8"} + ] + },{ + "name": "testnewelec", + "base": "", + "fields": [] + },{ + "name": "tmpvotennn", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"}, + {"name":"tickets", "type":"int64"} + ] + },{ + "name": "setram", + "base": "", + "fields": [ + {"name":"max_ram_size", "type":"uint64"} + ] + },{ + "name": "regproxy", + "base": "", + "fields": [ + {"name":"proxy", "type":"account_name"}, + {"name":"isproxy", "type":"bool"} + ] + },{ + "name": "voteproducer", + "base": "", + "fields": [ + {"name":"voter", "type":"account_name"}, + {"name":"proxy", "type":"account_name"}, + {"name":"producers", "type":"account_name[]"} + ] + },{ + "name": "voter_info", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"}, + {"name":"proxy", "type":"account_name"}, + {"name":"producers", "type":"account_name[]"}, + {"name":"staked", "type":"int64"}, + {"name":"last_vote_weight", "type":"float64"}, + {"name":"proxied_vote_weight", "type":"float64"}, + {"name":"is_proxy", "type":"bool"} + ] + },{ + "name": "claimrewards", + "base": "", + "fields": [ + {"name":"owner", "type":"account_name"} + ] + },{ + "name": "rewardprods", + "base": "", + "fields": [] + },{ + "name": "setpriv", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"is_priv", "type":"int8"} + ] + },{ + "name": "rmvproducer", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"} + ] + },{ + "name": "set_account_limits", + "base": "", + "fields": [ + {"name":"account", "type":"account_name"}, + {"name":"ram_bytes", "type":"int64"}, + {"name":"net_weight", "type":"int64"}, + {"name":"cpu_weight", "type":"int64"} + ] + },{ + "name": "set_global_limits", + "base": "", + "fields": [ + {"name":"cpu_usec_per_period", "type":"int64"} + ] + },{ + "name": "producer_key", + "base": "", + "fields": [ + {"name":"producer_name", "type":"account_name"}, + {"name":"block_signing_key", "type":"public_key"} + ] + },{ + "name": "set_producers", + "base": "", + "fields": [ + {"name":"schedule", "type":"producer_key[]"} + ] + },{ + "name": "require_auth", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"} + ] + },{ + "name": "setparams", + "base": "", + "fields": [ + {"name":"params", "type":"blockchain_parameters"} + ] + },{ + "name": "connector", + "base": "", + "fields": [ + {"name":"balance", "type":"asset"}, + {"name":"weight", "type":"float64"} + ] + },{ + "name": "exchange_state", + "base": "", + "fields": [ + {"name":"supply", "type":"asset"}, + {"name":"base", "type":"connector"}, + {"name":"quote", "type":"connector"} + ] + }, { + "name": "namebid_info", + "base": "", + "fields": [ + {"name":"newname", "type":"account_name"}, + {"name":"high_bidder", "type":"account_name"}, + {"name":"high_bid", "type":"int64"}, + {"name":"last_bid_time", "type":"uint64"} + ] + } + ], + "actions": [{ + "name": "newaccount", + "type": "newaccount", + "ricardian_contract": "" + },{ + "name": "setcode", + "type": "setcode", + "ricardian_contract": "" + },{ + "name": "setabi", + "type": "setabi", + "ricardian_contract": "" + },{ + "name": "updateauth", + "type": "updateauth", + "ricardian_contract": "" + },{ + "name": "deleteauth", + "type": "deleteauth", + "ricardian_contract": "" + },{ + "name": "linkauth", + "type": "linkauth", + "ricardian_contract": "" + },{ + "name": "unlinkauth", + "type": "unlinkauth", + "ricardian_contract": "" + },{ + "name": "canceldelay", + "type": "canceldelay", + "ricardian_contract": "" + },{ + "name": "onerror", + "type": "onerror", + "ricardian_contract": "" + },{ + "name": "buyrambytes", + "type": "buyrambytes", + "ricardian_contract": "" + },{ + "name": "buyram", + "type": "buyram", + "ricardian_contract": "" + },{ + "name": "sellram", + "type": "sellram", + "ricardian_contract": "" + },{ + "name": "delegatebw", + "type": "delegatebw", + "ricardian_contract": "" + },{ + "name": "undelegatebw", + "type": "undelegatebw", + "ricardian_contract": "" + },{ + "name": "refund", + "type": "refund", + "ricardian_contract": "" + },{ + "name": "regproducer", + "type": "regproducer", + "ricardian_contract": "" + },{ + "name": "setram", + "type": "setram", + "ricardian_contract": "" + },{ + "name": "bidname", + "type": "bidname", + "ricardian_contract": "" + },{ + "name": "unregprod", + "type": "unregprod", + "ricardian_contract": "" + },{ + "name": "clsprods2", + "type": "clsprods2", + "ricardian_contract": "" + },{ + "name": "seqproducer", + "type": "seqproducer", + "ricardian_contract": "" + },{ + "name": "testnewelec", + "type": "testnewelec", + "ricardian_contract": "" + },{ + "name": "tmpvotennn", + "type": "tmpvotennn", + "ricardian_contract": "" + },{ + "name": "regproxy", + "type": "regproxy", + "ricardian_contract": "" + },{ + "name": "voteproducer", + "type": "voteproducer", + "ricardian_contract": "" + },{ + "name": "claimrewards", + "type": "claimrewards", + "ricardian_contract": "" + },{ + "name": "rewardprods", + "type": "rewardprods", + "ricardian_contract": "" + },{ + "name": "setpriv", + "type": "setpriv", + "ricardian_contract": "" + },{ + "name": "rmvproducer", + "type": "rmvproducer", + "ricardian_contract": "" + },{ + "name": "setalimits", + "type": "set_account_limits", + "ricardian_contract": "" + },{ + "name": "setglimits", + "type": "set_global_limits", + "ricardian_contract": "" + },{ + "name": "setprods", + "type": "set_producers", + "ricardian_contract": "" + },{ + "name": "reqauth", + "type": "require_auth", + "ricardian_contract": "" + },{ + "name": "setparams", + "type": "setparams", + "ricardian_contract": "" + }], + "tables": [{ + "name": "producers", + "type": "producer_info", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["uint64"] + },{ + "name": "producersext", + "type": "producer_info_ext", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["uint64"] + },{ + "name": "producerseq", + "type": "producers_seq", + "index_type": "i64", + "key_names" : ["seq_num"], + "key_types" : ["uint64"] + },{ + "name": "global", + "type": "eosio_global_state", + "index_type": "i64", + "key_names" : [], + "key_types" : [] + },{ + "name": "globalext", + "type": "eosio_global_state2", + "index_type": "i64", + "key_names" : [], + "key_types" : [] + },{ + "name": "gcount", + "type": "eosio_global_count", + "index_type": "i64", + "key_names" : [], + "key_types" : [] + },{ + "name": "voters", + "type": "voter_info", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["account_name"] + },{ + "name": "userres", + "type": "user_resources", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["uint64"] + },{ + "name": "delband", + "type": "delegated_bandwidth", + "index_type": "i64", + "key_names" : ["to"], + "key_types" : ["uint64"] + },{ + "name": "rammarket", + "type": "exchange_state", + "index_type": "i64", + "key_names" : ["supply"], + "key_types" : ["uint64"] + },{ + "name": "refunds", + "type": "refund_request", + "index_type": "i64", + "key_names" : ["owner"], + "key_types" : ["uint64"] + },{ + "name": "namebids", + "type": "namebid_info", + "index_type": "i64", + "key_names" : ["newname"], + "key_types" : ["account_name"] + } + ], + "ricardian_clauses": [], + "abi_extensions": [] +} diff --git a/contracts/eosio.system_bak/eosio.system.cpp b/contracts/eosio.system_bak/eosio.system.cpp new file mode 100644 index 0000000000000000000000000000000000000000..38c8eb3b19b3d23d1a9a424d13e7eae591f52fd3 --- /dev/null +++ b/contracts/eosio.system_bak/eosio.system.cpp @@ -0,0 +1,215 @@ +#include "eosio.system.hpp" +#include + +#include "producer_pay.cpp" +#include "delegate_bandwidth.cpp" +#include "voting.cpp" +#include "exchange_state.cpp" + + +namespace eosiosystem { + + system_contract::system_contract( account_name s ) + :native(s), + _voters(_self,_self), + _producers(_self,_self), + _global(_self,_self), + _rammarket(_self,_self), + _producersext(_self,_self), + _globalex(_self,_self) + { + //print( "construct system\n" ); + _gstate = _global.exists() ? _global.get() : get_default_parameters(); + _gstateex = _globalex.exists() ? _globalex.get() : eosio_global_state2{}; + + auto itr = _rammarket.find(S(4,RAMCORE)); + + if( itr == _rammarket.end() ) { + auto system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount; + if( system_token_supply > 0 ) { + itr = _rammarket.emplace( _self, [&]( auto& m ) { + m.supply.amount = 100000000000000ll; + m.supply.symbol = S(4,RAMCORE); + m.base.balance.amount = int64_t(_gstate.free_ram()); + m.base.balance.symbol = S(0,RAM); + m.quote.balance.amount = system_token_supply / 1000; + m.quote.balance.symbol = CORE_SYMBOL; + }); + } + } else { + //print( "ram market already created" ); + } + } + + eosio_global_state system_contract::get_default_parameters() { + eosio_global_state dp; + get_blockchain_parameters(dp); + return dp; + } + + + system_contract::~system_contract() { + //print( "destruct system\n" ); + _global.set( _gstate, _self ); + _globalex.set( _gstateex, _self ); + //eosio_exit(0); + } + + void system_contract::setram( uint64_t max_ram_size ) { + require_auth( _self ); + + eosio_assert( _gstate.max_ram_size < max_ram_size, "ram may only be increased" ); /// decreasing ram might result market maker issues + eosio_assert( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" ); + eosio_assert( max_ram_size > _gstate.total_ram_bytes_reserved, "attempt to set max below reserved" ); + + auto delta = int64_t(max_ram_size) - int64_t(_gstate.max_ram_size); + auto itr = _rammarket.find(S(4,RAMCORE)); + + /** + * Increase or decrease the amount of ram for sale based upon the change in max + * ram size. + */ + _rammarket.modify( itr, 0, [&]( auto& m ) { + m.base.balance.amount += delta; + }); + + _gstate.max_ram_size = max_ram_size; + _global.set( _gstate, _self ); + } + + void system_contract::setparams( const eosio::blockchain_parameters& params ) { + require_auth( N(eosio) ); + (eosio::blockchain_parameters&)(_gstate) = params; + eosio_assert( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); + set_blockchain_parameters( params ); + } + + void system_contract::setpriv( account_name account, uint8_t ispriv ) { + require_auth( _self ); + set_privileged( account, ispriv ); + } + + void system_contract::rmvproducer( account_name producer ) { + require_auth( _self ); + auto prod = _producers.find( producer ); + eosio_assert( prod != _producers.end(), "producer not found" ); + _producers.modify( prod, 0, [&](auto& p) { + p.deactivate(); + }); + + change_producer_seq_info(producer, public_key(), false, false , ""); + } + + void system_contract::bidname( account_name bidder, account_name newname, asset bid ) { + require_auth( bidder ); + eosio_assert( eosio::name_suffix(newname) == newname, "you can only bid on top-level suffix" ); + eosio_assert( newname != 0, "the empty name is not a valid account name to bid on" ); + eosio_assert( (newname & 0xFull) == 0, "13 character names are not valid account names to bid on" ); + eosio_assert( (newname & 0x1F0ull) == 0, "accounts with 12 character names and no dots can be created without bidding required" ); + eosio_assert( !is_account( newname ), "account already exists" ); + eosio_assert( bid.symbol == asset().symbol, "asset must be system token" ); + eosio_assert( bid.amount > 0, "insufficient bid" ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {bidder,N(active)}, + { bidder, N(eosio.names), bid, std::string("bid name ")+(name{newname}).to_string() } ); + + name_bid_table bids(_self,_self); + print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" ); + auto current = bids.find( newname ); + if( current == bids.end() ) { + bids.emplace( bidder, [&]( auto& b ) { + b.newname = newname; + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time(); + }); + } else { + eosio_assert( current->high_bid > 0, "this auction has already closed" ); + eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" ); + eosio_assert( current->high_bidder != bidder, "account is already highest bidder" ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.names),N(active)}, + { N(eosio.names), current->high_bidder, asset(current->high_bid), + std::string("refund bid on name ")+(name{newname}).to_string() } ); + + bids.modify( current, bidder, [&]( auto& b ) { + b.high_bidder = bidder; + b.high_bid = bid.amount; + b.last_bid_time = current_time(); + }); + } + } + + /** + * Called after a new account is created. This code enforces resource-limits rules + * for new accounts as well as new account naming conventions. + * + * Account names containing '.' symbols must have a suffix equal to the name of the creator. + * This allows users who buy a premium name (shorter than 12 characters with no dots) to be the only ones + * who can create accounts with the creator's name as a suffix. + * + */ + void native::newaccount( account_name creator, + account_name newact + /* no need to parse authorities + const authority& owner, + const authority& active*/ ) { + + if( creator != _self ) { + auto tmp = newact >> 4; + bool has_dot = false; + + for( uint32_t i = 0; i < 12; ++i ) { + has_dot |= !(tmp & 0x1f); + tmp >>= 5; + } + if( has_dot ) { // or is less than 12 characters + auto suffix = eosio::name_suffix(newact); + if( suffix == newact ) { + name_bid_table bids(_self,_self); + auto current = bids.find( newact ); + eosio_assert( current != bids.end(), "no active bid for name" ); + eosio_assert( current->high_bidder == creator, "only highest bidder can claim" ); + eosio_assert( current->high_bid < 0, "auction for name is not closed yet" ); + bids.erase( current ); + } else { + eosio_assert( creator == suffix, "only suffix may create this account" ); + } + } + } + + user_resources_table userres( _self, newact); + + userres.emplace( newact, [&]( auto& res ) { + res.owner = newact; + }); + + set_resource_limits( newact, 0, 0, 0 ); + + //##YTA-Change start: + global_count_singleton global(_self, _self); + eosio_global_count gstate; + if(global.exists()) { + gstate = global.get(); + } + gstate.total_accounts += 1; + global.set( gstate, _self ); + //##YTA-Change end: + + } + +} /// eosio.system + + +EOSIO_ABI( eosiosystem::system_contract, + // native.hpp (newaccount definition is actually in eosio.system.cpp) + (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror) + // eosio.system.cpp + (setram)(setparams)(setpriv)(rmvproducer)(bidname) + // delegate_bandwidth.cpp + (buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund) + // voting.cpp + (regproducer)(unregprod)(voteproducer)(regproxy)(clsprods2)(seqproducer)(testnewelec) + // producer_pay.cpp + (onblock)(claimrewards)(rewardprods) +) diff --git a/contracts/eosio.system_bak/eosio.system.hpp b/contracts/eosio.system_bak/eosio.system.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e635e497b31766a52b0ac60f170f48214e71314a --- /dev/null +++ b/contracts/eosio.system_bak/eosio.system.hpp @@ -0,0 +1,360 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace eosiosystem { + + using eosio::asset; + using eosio::indexed_by; + using eosio::const_mem_fun; + using eosio::block_timestamp; + + struct name_bid { + account_name newname; + account_name high_bidder; + int64_t high_bid = 0; ///< negative high_bid == closed auction waiting to be claimed + uint64_t last_bid_time = 0; + + auto primary_key()const { return newname; } + uint64_t by_high_bid()const { return static_cast(-high_bid); } + }; + + typedef eosio::multi_index< N(namebids), name_bid, + indexed_by > + > name_bid_table; + + + struct eosio_global_state : eosio::blockchain_parameters { + uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } + + uint64_t max_ram_size = 64ll*1024 * 1024 * 1024; + uint64_t total_ram_bytes_reserved = 0; + int64_t total_ram_stake = 0; + + block_timestamp last_producer_schedule_update; + uint64_t last_pervote_bucket_fill = 0; + int64_t pervote_bucket = 0; + int64_t perblock_bucket = 0; + uint32_t total_unpaid_blocks = 0; /// all blocks which have been produced but not paid + int64_t total_activated_stake = 0; + uint64_t thresh_activated_stake_time = 0; + uint16_t last_producer_schedule_size = 0; + double total_producer_vote_weight = 0; /// the sum of all producer votes + block_timestamp last_name_close; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE_DERIVED( eosio_global_state, eosio::blockchain_parameters, + (max_ram_size)(total_ram_bytes_reserved)(total_ram_stake) + (last_producer_schedule_update)(last_pervote_bucket_fill) + (pervote_bucket)(perblock_bucket)(total_unpaid_blocks)(total_activated_stake)(thresh_activated_stake_time) + (last_producer_schedule_size)(total_producer_vote_weight)(last_name_close) ) + }; + + //##YTA-Change start: + struct eosio_global_state2 { + int64_t perbase_bucket = 0; + uint32_t total_unpaid_base_cnt = 0; + uint64_t last_claim_time = 0; + + EOSLIB_SERIALIZE( eosio_global_state2, (perbase_bucket)(total_unpaid_base_cnt)(last_claim_time)) + }; + + struct eosio_global_count { + uint64_t total_accounts = 1; + + EOSLIB_SERIALIZE( eosio_global_count, (total_accounts) ) + }; + //##YTA-Change end: + + struct producer_info { + account_name owner; + double total_votes = 0; + eosio::public_key producer_key; /// a packed public key object + bool is_active = true; + std::string url; + uint32_t unpaid_blocks = 0; + uint64_t last_claim_time = 0; + uint16_t location = 0; + + uint64_t primary_key()const { return owner; } + double by_votes()const { return is_active ? -total_votes : total_votes; } + bool active()const { return is_active; } + void deactivate() { producer_key = public_key(); is_active = false; } + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) + (unpaid_blocks)(last_claim_time)(location) ) + }; + + //##YTA-Change start: + struct producer_info_ext { + account_name owner; + uint16_t seq_num = 1; // from 1 to 21 + int64_t out_votes = 0; + uint32_t unpaid_base_cnt = 0; + uint64_t primary_key()const { return owner; } + + EOSLIB_SERIALIZE( producer_info_ext, (owner)(seq_num)(out_votes)(unpaid_base_cnt)) + + }; + + struct prod_meta { + account_name owner; + double total_votes = 0; // total votes + eosio::public_key producer_key; /// a packed public key object + int64_t all_stake = 0; // total original votes (buy yta amount) + bool is_active = true; + std::string url; + uint16_t location = 0; + + EOSLIB_SERIALIZE( prod_meta, (owner)(total_votes)(producer_key)(all_stake)(is_active)(url)(location) ) + }; + + struct producers_seq { + uint16_t seq_num = 1; // from 1 to 21 + bool is_org = false; + prod_meta prods_l1; // only one + std::vector prods_l2; //max 5 + std::vector prods_l3; + std::vector prods_all; + + uint64_t primary_key()const { return seq_num; } + + EOSLIB_SERIALIZE( producers_seq, (seq_num)(is_org)(prods_l1)(prods_l2)(prods_l3)(prods_all) ) + + }; + //##YTA-Change end: + + //##YTA-Change start: + struct yta_prod_info { + account_name owner; + double total_votes = 0; // total votes + eosio::public_key producer_key; /// a packed public key object + int64_t all_stake = 0; // total original votes (buy yta amount) + bool is_active = true; + std::string url; + uint16_t location = 0; + bool is_in_grace; //是否处在补齐投票的宽限期 + uint64_t grace_start_time = 0; //宽限期的开始时间 + + EOSLIB_SERIALIZE( yta_prod_info, (owner)(total_votes)(producer_key)(all_stake)(is_active)(url)(location)(is_in_grace)(grace_start_time) ) + + }; + + struct all_prods_level { + std::vector prods_l1; //max 21 + std::vector prods_l2; //max 105 + std::vector prods_l3; + + EOSLIB_SERIALIZE( all_prods_level, (prods_l1)(prods_l2)(prods_l3) ) + }; + typedef eosio::singleton all_prods_singleton; + + //##YTA-Change end: + + struct voter_info { + account_name owner = 0; /// the voter + account_name proxy = 0; /// the proxy set by the voter, if any + std::vector producers; /// the producers approved by this voter if no proxy set + int64_t staked = 0; + + /** + * 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 = 0; /// 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 reserved1 = 0; + time reserved2 = 0; + eosio::asset reserved3; + + 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)(reserved1)(reserved2)(reserved3) ) + }; + + typedef eosio::multi_index< N(voters), voter_info> voters_table; + + + typedef eosio::multi_index< N(producers), producer_info, + indexed_by > + > producers_table; + + //##YTA-Change start: + typedef eosio::multi_index< N(producersext), producer_info_ext> producers_ext_table; + typedef eosio::multi_index< N(producerseq), producers_seq> producers_seq_table; + //##YTA-Change end: + + typedef eosio::singleton global_state_singleton; + + //##YTA-Change start: + typedef eosio::singleton global_state2_singleton; + typedef eosio::singleton global_count_singleton; + //##YTA-Change end: + + // static constexpr uint32_t max_inflation_rate = 5; // 5% annual inflation + static constexpr uint32_t seconds_per_day = 24 * 3600; + static constexpr uint64_t system_token_symbol = CORE_SYMBOL; + + class system_contract : public native { + private: + voters_table _voters; + producers_table _producers; + global_state_singleton _global; + eosio_global_state _gstate; + rammarket _rammarket; + + //##YTA-Change start: + producers_ext_table _producersext; + eosio_global_state2 _gstateex; + global_state2_singleton _globalex; + //##YTA-Change end: + + public: + system_contract( account_name s ); + ~system_contract(); + + // Actions: + void onblock( block_timestamp timestamp, account_name producer ); + // const block_header& header ); /// only parse first 3 fields of block header + + // functions defined in delegate_bandwidth.cpp + + /** + * Stakes SYS from the balance of 'from' for the benfit of 'receiver'. + * If transfer == true, then 'receiver' can unstake to their account + * Else 'from' can unstake at any time. + */ + void delegatebw( account_name from, account_name receiver, + asset stake_net_quantity, asset stake_cpu_quantity, bool transfer ); + + + /** + * Decreases the total tokens delegated by from to receiver and/or + * frees the memory associated with the delegation if there is nothing + * left to delegate. + * + * This will cause an immediate reduction in net/cpu bandwidth of the + * receiver. + * + * A transaction is scheduled to send the tokens back to 'from' after + * the staking period has passed. If existing transaction is scheduled, it + * will be canceled and a new transaction issued that has the combined + * undelegated amount. + * + * The 'from' account loses voting power as a result of this call and + * all producer tallies are updated. + */ + void undelegatebw( account_name from, account_name receiver, + asset unstake_net_quantity, asset unstake_cpu_quantity ); + + + /** + * Increases receiver's ram quota based upon current price and quantity of + * tokens provided. An inline transfer from receiver to system contract of + * tokens will be executed. + */ + void buyram( account_name buyer, account_name receiver, asset tokens ); + void buyrambytes( account_name buyer, account_name receiver, uint32_t bytes ); + + /** + * Reduces quota my bytes and then performs an inline transfer of tokens + * to receiver based upon the average purchase price of the original quota. + */ + void sellram( account_name receiver, int64_t bytes ); + + /** + * This action is called after the delegation-period to claim all pending + * unstaked tokens belonging to owner + */ + void refund( account_name owner ); + + // functions defined in voting.cpp + + void regproducer( const account_name producer, const public_key& producer_key, const std::string& url, uint16_t location ); + + void unregprod( const account_name producer ); + +//##YTA-Change start: + void clsprods2(); + + void seqproducer( const account_name producer, uint16_t seq , uint8_t level ); + + void tmpvotennn( const account_name producer, int64_t tickets ); + + void testnewelec(); +//##YTA-Change end: + + void setram( uint64_t max_ram_size ); + + void voteproducer( const account_name voter, const account_name proxy, const std::vector& producers ); + + void regproxy( const account_name proxy, bool isproxy ); + + void setparams( const eosio::blockchain_parameters& params ); + + // functions defined in producer_pay.cpp + void claimrewards( const account_name& owner ); + void rewardprods(); + + void setpriv( account_name account, uint8_t ispriv ); + + void rmvproducer( account_name producer ); + + void bidname( account_name bidder, account_name newname, asset bid ); + private: + void update_elected_producers( block_timestamp timestamp ); + +//##YTA-Change start: + void update_elected_producers_yta2( block_timestamp timestamp ); + + void update_elected_producers_yta( block_timestamp timestamp ); + + std::pair getProducerForSeq(uint64_t seq_num ); + + void rm_producer_seq( const account_name producer, uint16_t seq ); + + void add_producer_seq( const account_name producer, uint16_t seq , uint8_t level ); + + void change_producer_seq_info( const account_name producer, const eosio::public_key& producer_key, bool isactive, bool seturl, const std::string& url); + + void update_producers_seq_totalvotes( uint16_t seq_num, account_name owner, double total_votes); +//##YTA-Change end: + + // Implementation details: + + //defind in delegate_bandwidth.cpp + void changebw( account_name from, account_name receiver, + asset stake_net_quantity, asset stake_cpu_quantity, bool transfer ); + + //defined in voting.hpp + static eosio_global_state get_default_parameters(); + + void update_votes( const account_name voter, const account_name proxy, const std::vector& producers, bool voting ); + + // defined in voting.cpp + void propagate_weight_change( const voter_info& voter ); + }; + +} /// eosiosystem diff --git a/contracts/eosio.system_bak/exchange_state.cpp b/contracts/eosio.system_bak/exchange_state.cpp new file mode 100644 index 0000000000000000000000000000000000000000..621d3e714b36159b77da2f7a837a9137a5de5e82 --- /dev/null +++ b/contracts/eosio.system_bak/exchange_state.cpp @@ -0,0 +1,85 @@ +#include + +namespace eosiosystem { + asset exchange_state::convert_to_exchange( connector& c, asset in ) { + + real_type R(supply.amount); + real_type C(c.balance.amount+in.amount); + real_type F(c.weight/1000.0); + real_type T(in.amount); + real_type ONE(1.0); + + real_type E = -R * (ONE - std::pow( ONE + T / C, F) ); + //print( "E: ", E, "\n"); + int64_t issued = int64_t(E); + + supply.amount += issued; + c.balance.amount += in.amount; + + return asset( issued, supply.symbol ); + } + + asset exchange_state::convert_from_exchange( connector& c, asset in ) { + eosio_assert( in.symbol== supply.symbol, "unexpected asset symbol input" ); + + real_type R(supply.amount - in.amount); + real_type C(c.balance.amount); + real_type F(1000.0/c.weight); + real_type E(in.amount); + real_type ONE(1.0); + + + // potentially more accurate: + // The functions std::expm1 and std::log1p are useful for financial calculations, for example, + // when calculating small daily interest rates: (1+x)n + // -1 can be expressed as std::expm1(n * std::log1p(x)). + // real_type T = C * std::expm1( F * std::log1p(E/R) ); + + real_type T = C * (std::pow( ONE + E/R, F) - ONE); + //print( "T: ", T, "\n"); + int64_t out = int64_t(T); + + supply.amount -= in.amount; + c.balance.amount -= out; + + return asset( out, c.balance.symbol ); + } + + asset exchange_state::convert( asset from, symbol_type to ) { + auto sell_symbol = from.symbol; + auto ex_symbol = supply.symbol; + auto base_symbol = base.balance.symbol; + auto quote_symbol = quote.balance.symbol; + + //print( "From: ", from, " TO ", asset( 0,to), "\n" ); + //print( "base: ", base_symbol, "\n" ); + //print( "quote: ", quote_symbol, "\n" ); + //print( "ex: ", supply.symbol, "\n" ); + + if( sell_symbol != ex_symbol ) { + if( sell_symbol == base_symbol ) { + from = convert_to_exchange( base, from ); + } else if( sell_symbol == quote_symbol ) { + from = convert_to_exchange( quote, from ); + } else { + eosio_assert( false, "invalid sell" ); + } + } else { + if( to == base_symbol ) { + from = convert_from_exchange( base, from ); + } else if( to == quote_symbol ) { + from = convert_from_exchange( quote, from ); + } else { + eosio_assert( false, "invalid conversion" ); + } + } + + if( to != from.symbol ) + return convert( from, to ); + + return from; + } + + + +} /// namespace eosiosystem diff --git a/contracts/eosio.system_bak/exchange_state.hpp b/contracts/eosio.system_bak/exchange_state.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3705a9b8b988d3fc055de072a611a80e851231bf --- /dev/null +++ b/contracts/eosio.system_bak/exchange_state.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace eosiosystem { + using eosio::asset; + using eosio::symbol_type; + + typedef double real_type; + + /** + * Uses Bancor math to create a 50/50 relay between two asset types. The state of the + * bancor exchange is entirely contained within this struct. There are no external + * side effects associated with using this API. + */ + struct exchange_state { + asset supply; + + struct connector { + asset balance; + double weight = .5; + + EOSLIB_SERIALIZE( connector, (balance)(weight) ) + }; + + connector base; + connector quote; + + uint64_t primary_key()const { return supply.symbol; } + + asset convert_to_exchange( connector& c, asset in ); + asset convert_from_exchange( connector& c, asset in ); + asset convert( asset from, symbol_type to ); + + EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) ) + }; + + typedef eosio::multi_index rammarket; + +} /// namespace eosiosystem diff --git a/contracts/eosio.system_bak/native.hpp b/contracts/eosio.system_bak/native.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e2bcb31957554d190d0cd985c8b165fdd46ef035 --- /dev/null +++ b/contracts/eosio.system_bak/native.hpp @@ -0,0 +1,112 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eosiosystem { + using eosio::permission_level; + using eosio::public_key; + + typedef std::vector bytes; + + struct permission_level_weight { + permission_level permission; + weight_type weight; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( permission_level_weight, (permission)(weight) ) + }; + + struct key_weight { + public_key key; + weight_type weight; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( key_weight, (key)(weight) ) + }; + + struct authority { + uint32_t threshold; + uint32_t delay_sec; + std::vector keys; + std::vector accounts; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE( authority, (threshold)(delay_sec)(keys)(accounts) ) + }; + + struct block_header { + uint32_t timestamp; + account_name producer; + uint16_t confirmed = 0; + block_id_type previous; + checksum256 transaction_mroot; + checksum256 action_mroot; + uint32_t schedule_version = 0; + eosio::optional new_producers; + + // explicit serialization macro is not necessary, used here only to improve compilation time + EOSLIB_SERIALIZE(block_header, (timestamp)(producer)(confirmed)(previous)(transaction_mroot)(action_mroot) + (schedule_version)(new_producers)) + }; + + + /* + * Method parameters commented out to prevent generation of code that parses input data. + */ + class native : public eosio::contract { + public: + + using eosio::contract::contract; + + /** + * Called after a new account is created. This code enforces resource-limits rules + * for new accounts as well as new account naming conventions. + * + * 1. accounts cannot contain '.' symbols which forces all acccounts to be 12 + * characters long without '.' until a future account auction process is implemented + * which prevents name squatting. + * + * 2. new accounts must stake a minimal number of tokens (as set in system parameters) + * therefore, this method will execute an inline buyram from receiver for newacnt in + * an amount equal to the current new account creation fee. + */ + void newaccount( account_name creator, + account_name newact + /* no need to parse authorites + const authority& owner, + const authority& active*/ ); + + + void updateauth( /*account_name account, + permission_name permission, + permission_name parent, + const authority& data*/ ) {} + + void deleteauth( /*account_name account, permission_name permission*/ ) {} + + void linkauth( /*account_name account, + account_name code, + action_name type, + permission_name requirement*/ ) {} + + void unlinkauth( /*account_name account, + account_name code, + action_name type*/ ) {} + + void canceldelay( /*permission_level canceling_auth, transaction_id_type trx_id*/ ) {} + + void onerror( /*const bytes&*/ ) {} + + }; +} diff --git a/contracts/eosio.system_bak/producer_pay.cpp b/contracts/eosio.system_bak/producer_pay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18ed144d8cff043c99458445405b7085f508e4e6 --- /dev/null +++ b/contracts/eosio.system_bak/producer_pay.cpp @@ -0,0 +1,348 @@ +#include "eosio.system.hpp" +#include +#include + +namespace eosiosystem { + + const int64_t min_pervote_daily_pay = 100'0000; + //##YTA-Change start: + //Change total vote rate from 15% to 1% for test network + //const int64_t min_activated_stake = 150'000'000'0000; + const int64_t min_activated_stake = 5'000'0000; + //##YTA-Change end: + const uint32_t blocks_per_year = 52*7*24*2*3600; // half seconds per year + const uint32_t seconds_per_year = 52*7*24*3600; + const uint32_t blocks_per_day = 2 * 24 * 3600; + const uint32_t blocks_per_hour = 2 * 3600; + const uint64_t useconds_per_day = 24 * 3600 * uint64_t(1000000); + const uint64_t useconds_per_year = seconds_per_year*1000000ll; + + const int64_t block_initial_timestamp = 1551369600ll; // epoch year 2019.03.01 unix timestamp 1551369600s + //yta seo total= yta_seo_year[i] * YTA_SEO_BASE + const uint32_t YTA_SEO_BASE = 10'0000; + const double YTA_PRECISION =10000.0000; + const uint32_t yta_seo_year[62] = { + 1000, 900, 800, 700, + 600, 600, 500, 500, + 400, 400, 300, 300, + 200, 200, 200, + 100, 100, 100, + 90, 90, 90, + 80, 80, 80, + 70, 70, 70, 70, + 60, 60, 60, 60, + 50, 50, 50, 50, 50, + 40, 40, 40, 40, 40, + 30, 30, 30, 30, 30, + 20, 20, 20, 20, 20, + 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9 + }; + + void system_contract::onblock( block_timestamp timestamp, account_name producer ) { + using namespace eosio; + + require_auth(N(eosio)); + + /** until activated stake crosses this threshold no new rewards are paid */ + if( _gstate.total_activated_stake < min_activated_stake ) + return; + + if( _gstate.last_pervote_bucket_fill == 0 ) /// start the presses + _gstate.last_pervote_bucket_fill = current_time(); + + + /** + * At startup the initial producer may not be one that is registered / elected + * and therefore there may be no producer object for them. + */ + auto prod = _producers.find(producer); + if ( prod != _producers.end() ) { + _gstate.total_unpaid_blocks++; + _producers.modify( prod, 0, [&](auto& p ) { + p.unpaid_blocks++; + }); + } + + //##YTA-Change start: + if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) { + for( auto it = _producersext.begin(); it != _producersext.end(); it++ ) { + _producersext.modify( it, 0, [&](auto& p ) { + p.unpaid_base_cnt++; + }); + _gstateex.total_unpaid_base_cnt++; + } + } + //##YTA-Change end: + + + //##YTA-Change start: + /// only update block producers once every minute, block_timestamp is in half seconds + //if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) { + /// update block producers once every two minute due to election strategy is more complex than before + if( timestamp.slot - _gstate.last_producer_schedule_update.slot > 120 ) { + //##YTA-Change end: + + update_elected_producers( timestamp ); + //update_elected_producers_yta( timestamp ); + + + if( (timestamp.slot - _gstate.last_name_close.slot) > blocks_per_day ) { + name_bid_table bids(_self,_self); + auto idx = bids.get_index(); + auto highest = idx.begin(); + if( highest != idx.end() && + highest->high_bid > 0 && + highest->last_bid_time < (current_time() - useconds_per_day) && + _gstate.thresh_activated_stake_time > 0 && + (current_time() - _gstate.thresh_activated_stake_time) > 14 * useconds_per_day ) { + _gstate.last_name_close = timestamp; + idx.modify( highest, 0, [&]( auto& b ){ + b.high_bid = -b.high_bid; + }); + } + } + } + } + + using namespace eosio; + void system_contract::claimrewards( const account_name& owner ) { + require_auth(_self); + //require_auth(owner); + + //@@@@@@@@@@@@@@@@@@@@ + + const auto& prod = _producers.get( owner ); + eosio_assert( prod.active(), "producer does not have an active key" ); + + eosio_assert( _gstate.total_activated_stake >= min_activated_stake, + "cannot claim rewards until the chain is activated (at least 15% of all tokens participate in voting)" ); + + auto ct = current_time(); + + eosio_assert( ct - prod.last_claim_time > useconds_per_day, "already claimed rewards within past day" ); + + const asset token_supply = token( N(eosio.token)).get_supply(symbol_type(system_token_symbol).name() ); + const auto usecs_since_last_fill = ct - _gstate.last_pervote_bucket_fill; + + print("usecs_since_last_fill: ", usecs_since_last_fill, "\n"); + print("_gstate.last_pervote_bucket_fill: ", _gstate.last_pervote_bucket_fill, "\n"); + print("now(): ", now(), "\n"); + + int idx_year = (int)((now()- block_initial_timestamp) / seconds_per_year); + auto seo_token = yta_seo_year[idx_year] * YTA_SEO_BASE; + + print("idx_year: ", idx_year, "\n"); + print("yta_seo_year[idx_year]: ", yta_seo_year[idx_year], "\n"); + print( "token_supply: ", token_supply, "\n"); + print("seo_token: ", seo_token, "\n"); + + if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > 0 ) { + auto new_tokens = static_cast(seo_token * YTA_PRECISION * double(usecs_since_last_fill)/double(useconds_per_year)); + print("new_token: ", new_tokens, "\n"); + auto to_per_base_pay = static_cast((new_tokens * 3) / 5); + auto to_producers = new_tokens - to_per_base_pay; + auto to_per_block_pay = to_producers / 2; + auto to_per_vote_pay = to_producers - to_per_block_pay; + + INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, + {N(eosio), asset(new_tokens), std::string("issue tokens for producer pay")} ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(hddbasefound), asset(to_per_base_pay), "fund per-base bucket" } ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(eosio.bpay), asset(to_per_block_pay), "fund per-block bucket" } ); + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(eosio.vpay), asset(to_per_vote_pay), "fund per-vote bucket" } ); + + _gstateex.perbase_bucket += to_per_base_pay; + _gstate.pervote_bucket += to_per_vote_pay; + _gstate.perblock_bucket += to_per_block_pay; + + _gstate.last_pervote_bucket_fill = ct; + } + + const auto& prodext = _producersext.get( owner ); + + int64_t producer_per_base_pay = 0; + if( _gstateex.total_unpaid_base_cnt > 0 ) { + producer_per_base_pay = (_gstateex.perbase_bucket * prodext.unpaid_base_cnt) / _gstateex.total_unpaid_base_cnt; + } + + int64_t producer_per_block_pay = 0; + if( _gstate.total_unpaid_blocks > 0 ) { + producer_per_block_pay = (_gstate.perblock_bucket * prod.unpaid_blocks) / _gstate.total_unpaid_blocks; + } + int64_t producer_per_vote_pay = 0; + if( _gstate.total_producer_vote_weight > 0 ) { + producer_per_vote_pay = int64_t((_gstate.pervote_bucket * prod.total_votes ) / _gstate.total_producer_vote_weight); + } + if( producer_per_vote_pay < min_pervote_daily_pay ) { + producer_per_vote_pay = 0; + } + + _gstateex.perbase_bucket -= producer_per_base_pay; + _gstate.pervote_bucket -= producer_per_vote_pay; + _gstate.perblock_bucket -= producer_per_block_pay; + _gstate.total_unpaid_blocks -= prod.unpaid_blocks; + _gstateex.total_unpaid_base_cnt -= prodext.unpaid_base_cnt; + + _producers.modify( prod, 0, [&](auto& p) { + p.last_claim_time = ct; + p.unpaid_blocks = 0; + }); + + _producersext.modify( prodext, 0, [&](auto& p) { + p.unpaid_base_cnt = 0; + }); + + if( producer_per_base_pay > 0 ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(hddbasefound),N(active)}, + { N(hddbasefound), owner, asset(producer_per_base_pay), std::string("producer base pay") } ); + } + if( producer_per_block_pay > 0 ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.bpay),N(active)}, + { N(eosio.bpay), owner, asset(producer_per_block_pay), std::string("producer block pay") } ); + } + if( producer_per_vote_pay > 0 ) { + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.vpay),N(active)}, + { N(eosio.vpay), owner, asset(producer_per_vote_pay), std::string("producer vote pay") } ); + } + } + + + void system_contract::rewardprods( ) { + //require_auth(_self); + require_auth(N(ytarewardusr)); + + auto ct = current_time(); + //eosio_assert( ct - _gstateex.last_claim_time > useconds_per_day, "already claimed rewards within past day" ); + _gstateex.last_claim_time = ct; + const auto usecs_since_last_fill = ct - _gstate.last_pervote_bucket_fill; + int idx_year = (int)((now()- block_initial_timestamp) / seconds_per_year); + auto seo_token = yta_seo_year[idx_year] * YTA_SEO_BASE; + + if( usecs_since_last_fill > 0 && _gstate.last_pervote_bucket_fill > 0 ) { + auto new_tokens = static_cast(seo_token * YTA_PRECISION * double(usecs_since_last_fill)/double(useconds_per_year)); + print("new_token: ", new_tokens, "\n"); + auto to_per_base_pay = static_cast((new_tokens * 3) / 5); + auto to_producers = new_tokens - to_per_base_pay; + auto to_per_block_pay = to_producers / 2; + auto to_per_vote_pay = to_producers - to_per_block_pay; + + + INLINE_ACTION_SENDER(eosio::token, issue)( N(eosio.token), {{N(eosio),N(active)}}, + {N(eosio), asset(new_tokens), std::string("issue tokens for producer pay")} ); + + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(hddbasefound), asset(to_per_base_pay), "fund per-base bucket" } ); + + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(eosio.bpay), asset(to_per_block_pay), "fund per-block bucket" } ); + + + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, + { N(eosio), N(eosio.vpay), asset(to_per_vote_pay), "fund per-vote bucket" } ); + + + _gstateex.perbase_bucket += to_per_base_pay; + _gstate.pervote_bucket += to_per_vote_pay; + _gstate.perblock_bucket += to_per_block_pay; + + _gstate.last_pervote_bucket_fill = ct; + } + + int64_t producer_total_base_pay = _gstateex.perbase_bucket; + int64_t producer_total_block_pay = _gstate.perblock_bucket; + int64_t producer_total_vote_pay = _gstate.pervote_bucket; + + print("producer_total_base_pay -- ", producer_total_base_pay , "\n"); + print("producer_total_block_pay -- ", producer_total_block_pay , "\n"); + print("producer_total_vote_pay -- ", producer_total_vote_pay , "\n"); + + + int64_t producer_already_base_pay = 0; + int64_t producer_already_block_pay = 0; + int64_t producer_already_vote_pay = 0; + + + uint32_t total_unpaid_blocks = _gstate.total_unpaid_blocks; + uint32_t total_unpaid_base_cnt = _gstateex.total_unpaid_base_cnt; + + for( auto it = _producers.begin(); it != _producers.end(); it++ ) { + if(!(it->active())) + continue; + auto& prodex = _producersext.get(it->owner); + int64_t producer_per_base_pay = 0; + if( _gstateex.total_unpaid_base_cnt > 0 ) { + producer_per_base_pay = (_gstateex.perbase_bucket * prodex.unpaid_base_cnt) / total_unpaid_base_cnt; + } + int64_t producer_per_block_pay = 0; + if( _gstate.total_unpaid_blocks > 0 ) { + producer_per_block_pay = (_gstate.perblock_bucket * it->unpaid_blocks) / total_unpaid_blocks; + } + int64_t producer_per_vote_pay = 0; + if( _gstate.total_producer_vote_weight > 0 ) { + producer_per_vote_pay = int64_t((_gstate.pervote_bucket * it->total_votes ) / _gstate.total_producer_vote_weight); + } + + print("producer_per_base_pay -- ", producer_per_base_pay , "\n"); + print("producer_per_block_pay -- ", producer_per_block_pay , "\n"); + print("producer_per_vote_pay -- ", producer_per_vote_pay , "\n"); + + + _gstate.total_unpaid_blocks -= it->unpaid_blocks; + _gstateex.total_unpaid_base_cnt -= prodex.unpaid_base_cnt; + + _producers.modify( it, 0, [&](auto& p) { + p.last_claim_time = ct; + p.unpaid_blocks = 0; + }); + + _producersext.modify( prodex, 0, [&](auto& p) { + p.unpaid_base_cnt = 0; + }); + + + if( producer_per_base_pay > 0 && ((producer_per_base_pay + producer_already_base_pay) <= producer_total_base_pay) ) { + producer_already_base_pay += producer_per_base_pay; + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(hddbasefound),N(active)}, + { N(hddbasefound), it->owner, asset(producer_per_base_pay), std::string("producer base pay") } ); + } + + if( producer_per_block_pay > 0 && ((producer_per_block_pay + producer_already_block_pay) <= producer_total_block_pay) ) { + producer_already_block_pay += producer_per_block_pay; + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.bpay),N(active)}, + { N(eosio.bpay), it->owner, asset(producer_per_block_pay), std::string("producer block pay") } ); + } + + if( producer_per_vote_pay > 0 && ((producer_per_vote_pay + producer_already_vote_pay) <= producer_total_vote_pay) ) { + producer_already_vote_pay += producer_per_vote_pay; + INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio.vpay),N(active)}, + { N(eosio.vpay), it->owner, asset(producer_per_vote_pay), std::string("producer vote pay") } ); + } + + } + + + _gstateex.perbase_bucket -= producer_already_base_pay; + _gstate.pervote_bucket -= producer_already_vote_pay; + _gstate.perblock_bucket -= producer_already_block_pay; + + if(_gstateex.perbase_bucket < 0 ) + _gstateex.perbase_bucket = 0; + + if(_gstate.pervote_bucket < 0 ) + _gstate.pervote_bucket = 0; + + if(_gstate.perblock_bucket < 0 ) + _gstate.perblock_bucket = 0; + + } + + +} //namespace eosiosystem diff --git a/contracts/eosio.system_bak/voting.cpp b/contracts/eosio.system_bak/voting.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63a804325ed1fe96d96eae6da9eb62d7c2f187d2 --- /dev/null +++ b/contracts/eosio.system_bak/voting.cpp @@ -0,0 +1,999 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ +#include "eosio.system.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace eosiosystem { + using eosio::indexed_by; + using eosio::const_mem_fun; + using eosio::bytes; + using eosio::print; + using eosio::singleton; + using eosio::transaction; + + /** + * This method will create a producer_config and producer_info object for 'producer' + * + * @pre producer is not already registered + * @pre producer to register is an account + * @pre authority of producer to register + * + */ + void system_contract::regproducer( const account_name producer, const eosio::public_key& producer_key, const std::string& url, uint16_t location ) { + eosio_assert( url.size() < 512, "url too long" ); + eosio_assert( producer_key != eosio::public_key(), "public key should not be the default value" ); + /* + require_auth( producer ); + + auto prod = _producers.find( producer ); + + if ( prod != _producers.end() ) { + _producers.modify( prod, producer, [&]( producer_info& info ){ + info.producer_key = producer_key; + info.is_active = true; + info.url = url; + info.location = location; + }); + + change_producer_seq_info(producer, producer_key, true, true, url); + } else { + _producers.emplace( producer, [&]( producer_info& info ){ + info.owner = producer; + info.total_votes = 0; + info.producer_key = producer_key; + info.is_active = true; + info.url = url; + info.location = location; + }); + } + */ + + require_auth( _self ); + + auto prod = _producers.find( producer ); + + if ( prod != _producers.end() ) { + _producers.modify( prod, _self, [&]( producer_info& info ){ + info.producer_key = producer_key; + info.is_active = true; + info.url = url; + info.location = location; + }); + + change_producer_seq_info(producer, producer_key, true, true, url); + } else { + _producers.emplace( _self, [&]( producer_info& info ){ + info.owner = producer; + info.total_votes = 0; + info.producer_key = producer_key; + info.is_active = true; + info.url = url; + info.location = location; + }); + } + + } + + void system_contract::unregprod( const account_name producer ) { + require_auth( producer ); + + ///@@@@@@@@@@@@@@@@@@@@@ + return; + + const auto& prod = _producers.get( producer, "producer not found" ); + + _producers.modify( prod, 0, [&]( producer_info& info ){ + info.deactivate(); + }); + + change_producer_seq_info(producer, public_key(), false, false, ""); + } +//##YTA-Change start: + void system_contract::clsprods2() { + require_auth( _self ); + + while (_producersext.begin() != _producersext.end()) { + auto it = _producersext.begin(); + //it->out_votes + const auto& prod = _producers.get( it->owner, "producer not found" ); + _producers.modify( prod, 0, [&]( producer_info& info ){ + info.total_votes -= it->out_votes; + }); + _gstate.total_producer_vote_weight -= it->out_votes; + _producersext.erase(_producersext.begin()); + } + + for( uint16_t seq = 1; seq <= 21; seq++ ) { + producers_seq_table _prod_seq( _self, seq ); + if( _prod_seq.begin() != _prod_seq.end() ) + _prod_seq.erase(_prod_seq.begin()); + } + + _gstateex.total_unpaid_base_cnt = 0; + + } + + void system_contract::seqproducer( const account_name producer, uint16_t seq , uint8_t level ) { + require_auth( _self ); + + //const auto& prod = _producers.get( producer, "producer not found" ); + auto itp = _producers.find(producer); + eosio_assert( itp != _producers.end() , "producer not found"); + + eosio_assert(seq >= 1 && seq <= 21 , "invalidate seq number"); + eosio_assert(level >= 1 && level <= 3 , "invalidate level number"); + //const auto& prod = _producers.get( producer, "producer not found" ); + + auto it = _producersext.find(producer); + if (it == _producersext.end()) { + _producersext.emplace(_self, [&](auto &row) { + row.owner = producer; + row.seq_num = seq; + }); + add_producer_seq(producer, seq, level); + } else { + uint16_t old_seq = it->seq_num; + _producersext.modify(it, _self, [&](auto &row) { + row.seq_num = seq; + }); + rm_producer_seq(producer, old_seq); + add_producer_seq(producer, seq, level); + } + } + + void system_contract::rm_producer_seq(const account_name producer, uint16_t seq) { + producers_seq_table _prodseq(_self, seq); + auto ps_itr = _prodseq.find (seq); + if( ps_itr == _prodseq.end() ) + return; + _prodseq.modify( ps_itr, _self, [&]( producers_seq& info ){ + if(info.prods_l1.owner == producer) { + info.prods_l1.owner = 0; + info.prods_l1.producer_key = public_key(); + info.prods_l1.all_stake = 0; + info.prods_l1.total_votes = 0; + info.prods_l1.is_active = false; + info.prods_l1.url = ""; + info.is_org = false; + } + + for( auto it2 = info.prods_l2.begin(); it2 != info.prods_l2.end(); it2++ ) { + if(it2->owner == producer) { + info.prods_l2.erase(it2); + break; + } + } + + for( auto it3 = info.prods_l3.begin(); it3 != info.prods_l3.end(); it3++ ) { + if(it3->owner == producer) { + info.prods_l3.erase(it3); + break; + } + } + + for( auto itall = info.prods_all.begin(); itall != info.prods_all.end(); itall++ ) { + if(itall->owner == producer) { + info.prods_all.erase(itall); + break; + } + } + }); + } + + void system_contract::add_producer_seq( const account_name producer, uint16_t seq , uint8_t level ) { + producers_seq_table _prodseq(_self, seq); + prod_meta prodm; + //need retrive from system producers table + const auto& prod = _producers.get( producer, "producer not found" ); + prodm.owner = producer; + prodm.producer_key = prod.producer_key; + prodm.all_stake = (int64_t)prod.total_votes; + prodm.total_votes = prod.total_votes; + prodm.is_active = prod.is_active; + prodm.url = prod.url; + auto ps_itr = _prodseq.find (seq); + if( ps_itr == _prodseq.end() ) { + _prodseq.emplace(_self, [&](auto &row) { + row.seq_num = seq; + if(level == 1) + row.is_org = true; + row.prods_all.push_back(prodm); + if(level == 1) { + row.prods_l1 = prodm; + } else if(level == 2) { + row.prods_l2.push_back(prodm); + } else if(level == 3) { + row.prods_l3.push_back(prodm); + } + }); + } else { + _prodseq.modify(ps_itr, _self, [&](auto &row) { + if(level == 1) + row.is_org = true; + row.prods_all.push_back(prodm); + if(level == 1) { + row.prods_l1 = prodm; + } else if(level == 2) { + row.prods_l2.push_back(prodm); + } else if(level == 3) { + row.prods_l3.push_back(prodm); + } + + }); + } + } + + void system_contract::change_producer_seq_info( const account_name producer, const eosio::public_key& producer_key, bool isactive, bool seturl, const std::string& url) { + auto it = _producersext.find(producer); + + if (it == _producersext.end()) + return; + + uint16_t seq = it->seq_num; + producers_seq_table _prodseq(_self, seq); + auto ps_itr = _prodseq.find (seq); + if( ps_itr == _prodseq.end() ) + return; + + _prodseq.modify( ps_itr, _self, [&]( producers_seq& info ){ + if(info.prods_l1.owner == producer) { + info.prods_l1.is_active = isactive; + info.prods_l1.producer_key = producer_key; + if(seturl) + info.prods_l1.url = url; + } + + for( auto it2 = info.prods_l2.begin(); it2 != info.prods_l2.end(); it2++ ) { + if(it2->owner == producer) { + it2->is_active = isactive; + it2->producer_key = producer_key; + if(seturl) + it2->url = url; + break; + } + } + + for( auto it3 = info.prods_l3.begin(); it3 != info.prods_l3.end(); it3++ ) { + if(it3->owner == producer) { + it3->is_active = isactive; + it3->producer_key = producer_key; + if(seturl) + it3->url = url; + break; + } + } + + for( auto itall = info.prods_all.begin(); itall != info.prods_all.end(); itall++ ) { + if(itall->owner == producer) { + itall->is_active = isactive; + itall->producer_key = producer_key; + if(seturl) + itall->url = url; + break; + } + } + }); + + } + + void system_contract::update_producers_seq_totalvotes( uint16_t seq_num, account_name owner, double total_votes) { + + producers_seq_table _prodseq(_self, seq_num); + auto ps_itr = _prodseq.find (seq_num); + + if( ps_itr == _prodseq.end() ) + return; + + _prodseq.modify( ps_itr, _self, [&]( producers_seq& info ){ + if( info.prods_l1.owner == owner ) { + info.prods_l1.total_votes = total_votes; + info.prods_l1.all_stake = (int64_t)total_votes; + //return; + } + + for(auto it = info.prods_l2.begin(); it != info.prods_l2.end(); it++) { + if(it->owner == owner) { + it->total_votes = total_votes; + it->all_stake = (int64_t)total_votes; + break; + } + } + + for(auto it = info.prods_l3.begin(); it != info.prods_l3.end(); it++) { + if(it->owner == owner) { + it->total_votes = total_votes; + it->all_stake = (int64_t)total_votes; + break; + } + } + + for(auto it = info.prods_all.begin(); it != info.prods_all.end(); it++) { + if(it->owner == owner) { + it->total_votes = total_votes; + it->all_stake = (int64_t)total_votes; + break; + } + } + + }); + } + + void system_contract::testnewelec() { + require_auth( _self ); + + block_timestamp block_time; + update_elected_producers_yta2( block_time ); + + + +/* + std::vector< std::pair > top_producers; + top_producers.reserve(21); + + + for( uint16_t seq_num = 1; seq_num <= 21 ; seq_num++ ) { + std::pair ppinfo = getProducerForSeq( seq_num ); + if( ppinfo.first.producer_name != 0 ) { + top_producers.emplace_back( ppinfo ); + } + } + + if ( top_producers.size() < _gstate.last_producer_schedule_size ) { + return; + } + + /// sort by producer name + std::sort( top_producers.begin(), top_producers.end() ); + + std::vector producers; + + producers.reserve(top_producers.size()); + for( const auto& item : top_producers ) + producers.push_back(item.first); + + + print("producers start------------------------------\n"); + for( const auto& item : producers ) { + print("producer -", (name{item.producer_name}), "--"); + + //std::string str(std::begin(item.block_signing_key.data), std::end(item.block_signing_key.data)); + //for(size_t i=0; i<33; i++) { + // char c = item.block_signing_key.data[i]; + // printf("%c",c); + //} + //print(str); + + print("\n"); + } + print("producers end------------------------------\n"); +*/ + + + } + + void system_contract::tmpvotennn( const account_name producer, int64_t tickets ) { + require_auth( _self ); + + const auto& prod = _producers.get( producer, "producer not found" ); + //auto it = _producers.find(producer); + //eosio_assert( it != _producers.end() , "producer not found"); + + int64_t vote_delta = 0; + _producers.modify( prod, 0, [&]( producer_info& info ){ + auto pitr2 = _producersext.find( producer); + if( pitr2 != _producersext.end() ) { + vote_delta = tickets - pitr2->out_votes; + info.total_votes += vote_delta; + _producersext.modify( pitr2, 0, [&]( producer_info_ext& info2){ + info2.out_votes = tickets; + }); + update_producers_seq_totalvotes(pitr2->seq_num, producer, info.total_votes); + } + }); + _gstate.total_producer_vote_weight += vote_delta; + + } + + const uint64_t useconds_per_day_v = 24 * 3600 * uint64_t(1000000); + + void system_contract::update_elected_producers_yta2( block_timestamp block_time ) { + + all_prods_singleton _all_prods(_self, _self); + all_prods_level _all_prods_state; + + if (!_all_prods.exists()) + return; + + _all_prods_state = _all_prods.get(); + +/* + for(int i = 0 ; i < 3 ; i++) { + yta_prod_info info; + info.total_votes = 50000000000; + info.all_stake = 50000000000; + info.is_active = true; + info.is_in_grace = false; + _all_prods_state.prods_l1.push_back(info); + } + _all_prods_state.prods_l1[0].owner = N(producer1); + _all_prods_state.prods_l1[0].is_active = false; + _all_prods_state.prods_l1[1].owner = N(producer2); + _all_prods_state.prods_l1[1].is_in_grace = true; + _all_prods_state.prods_l1[1].total_votes = 10000000000; + _all_prods_state.prods_l1[2].owner = N(producer3); + + + for(int i = 0 ; i < 6 ; i++) { + yta_prod_info info; + info.total_votes = 20000000000; + info.all_stake = 20000000000; + info.is_active = true; + info.is_in_grace = false; + _all_prods_state.prods_l2.push_back(info); + } + _all_prods_state.prods_l2[0].owner = N(producer11); + _all_prods_state.prods_l2[1].owner = N(producer12); + _all_prods_state.prods_l2[2].owner = N(producer13); + _all_prods_state.prods_l2[3].owner = N(producer14); + _all_prods_state.prods_l2[3].is_in_grace = true; + _all_prods_state.prods_l2[3].total_votes = 15000000000; + _all_prods_state.prods_l2[4].owner = N(producer15); + _all_prods_state.prods_l2[5].owner = N(producer1a); + + for(int i = 0 ; i < 2 ; i++) { + yta_prod_info info; + info.total_votes = 10000000000; + info.all_stake = 10000000000; + info.is_active = true; + info.is_in_grace = false; + _all_prods_state.prods_l3.push_back(info); + } + _all_prods_state.prods_l3[0].owner = N(producer21); + _all_prods_state.prods_l3[0].total_votes = 21000000000; + _all_prods_state.prods_l3[1].owner = N(producer22); + + print("before-----------------------------------\n"); + print("level 1-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + + print("level 1 again-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } +*/ + + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end();) { + bool is_remove = false; + if(!it->is_active) + is_remove = true; + + //print("-----level1 down--", (name{it->owner}), "---",(int64_t)it->total_votes ,"\n"); + if((int64_t)it->total_votes < 50000000000) { + //print("-----level1 down--", (name{it->owner}), "votes not enough\n"); + if(it->is_in_grace) { + if(current_time() - it->grace_start_time > useconds_per_day_v) { + is_remove = true; + it->is_in_grace = false; + } + + } else { + it->is_in_grace = true; + auto ct = current_time(); + it->grace_start_time = ct; + } + } else { + it->is_in_grace = false; + } + + if(is_remove) { + _all_prods_state.prods_l3.push_back(*it); + it = _all_prods_state.prods_l1.erase(it); + } else { + ++it; + } + } + +/* + print("step 1-----------------------------------\n"); + print("level 1-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } +*/ + + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end();) { + bool is_remove = false; + if(!it->is_active) + is_remove = true; + //print("-----level2 down--", (name{it->owner}), "---",(int64_t)it->total_votes ,"\n"); + if((int64_t)it->total_votes < 20000000000) { + //print("-----level2 down--", (name{it->owner}), "votes not enough\n"); + if(it->is_in_grace) { + if(current_time() - it->grace_start_time > useconds_per_day_v) { + is_remove = true; + it->is_in_grace = false; + } + + } else { + it->is_in_grace = true; + auto ct = current_time(); + it->grace_start_time = ct; + } + } else { + it->is_in_grace = false; + } + + if(is_remove) { + _all_prods_state.prods_l3.push_back(*it); + it = _all_prods_state.prods_l2.erase(it); + } else { + ++it; + } + } + +/* + print("step 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } +*/ + + std::sort(_all_prods_state.prods_l2.begin(), _all_prods_state.prods_l2.end(), [&](yta_prod_info lhs, yta_prod_info rhs){return lhs.total_votes > rhs.total_votes;}); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end();) { + //print("-----level2 up--", (name{it->owner}), "---",(int64_t)it->total_votes ,"\n"); + if((int64_t)it->total_votes >= 50000000000) { + //print("-----level2 up--", (name{it->owner}), "votes execeed\n"); + if(_all_prods_state.prods_l1.size() < 21) { + _all_prods_state.prods_l1.push_back(*it); + it = _all_prods_state.prods_l2.erase(it); + } else { + break; + } + } else { + ++it; + } + } + +/* + print("step 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } +*/ + + std::sort(_all_prods_state.prods_l3.begin(), _all_prods_state.prods_l3.end(), [&](yta_prod_info lhs, yta_prod_info rhs){return lhs.total_votes > rhs.total_votes;}); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end();) { + //print("-----level3 up--", (name{it->owner}), "---",(int64_t)it->total_votes ,"\n"); + if((int64_t)it->total_votes >= 20000000000 && it->is_active) { + //print("-----level3 up--", (name{it->owner}), "votes execeed\n"); + if(_all_prods_state.prods_l2.size() < 105) { + _all_prods_state.prods_l2.push_back(*it); + it = _all_prods_state.prods_l3.erase(it); + } else { + break; + } + } else { + ++it; + } + } + + _all_prods.set(_all_prods_state, _self); + +/* + print("after-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 2-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l2.begin(); it != _all_prods_state.prods_l2.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + print("level 3-----------------------------------\n"); + for( auto it =_all_prods_state.prods_l3.begin(); it != _all_prods_state.prods_l3.end(); it++ ) { + print("producer - ", (name{it->owner}), "--", (int64_t)it->total_votes, " --\n"); + } + return; +*/ + + ///--------------------------------------------------- + + _gstate.last_producer_schedule_update = block_time; + + std::vector< std::pair > top_producers; + top_producers.reserve(21); + + for( auto it =_all_prods_state.prods_l1.begin(); it != _all_prods_state.prods_l1.end(); it++ ) { + top_producers.emplace_back( std::pair({{it->owner, it->producer_key}, it->location}) ); + } + + if ( top_producers.size() < _gstate.last_producer_schedule_size ) { + if(top_producers.size() < 7) + return; + } + + /// sort by producer name + std::sort( top_producers.begin(), top_producers.end() ); + + std::vector producers; + + producers.reserve(top_producers.size()); + for( const auto& item : top_producers ) + producers.push_back(item.first); + + bytes packed_schedule = pack(producers); + + + if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { + _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + } + + + } + + + void system_contract::update_elected_producers_yta( block_timestamp block_time ) { + _gstate.last_producer_schedule_update = block_time; + + std::vector< std::pair > top_producers; + top_producers.reserve(21); + + + for( uint16_t seq_num = 1; seq_num <= 21 ; seq_num++ ) { + std::pair ppinfo = getProducerForSeq( seq_num ); + if( ppinfo.first.producer_name != 0 ) { + top_producers.emplace_back( ppinfo ); + } + } + + if ( top_producers.size() < _gstate.last_producer_schedule_size ) { + return; + } + + /// sort by producer name + std::sort( top_producers.begin(), top_producers.end() ); + + std::vector producers; + + producers.reserve(top_producers.size()); + for( const auto& item : top_producers ) + producers.push_back(item.first); + + bytes packed_schedule = pack(producers); + + if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { + _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + } + + + } + + std::pair system_contract::getProducerForSeq(uint64_t seq_num ) { + producers_seq_table _prodseq(_self, seq_num); + auto ps_itr = _prodseq.find (seq_num); + if( ps_itr == _prodseq.end() ) + return std::pair({{0, eosio::public_key{}}, 0}); + + if (ps_itr->prods_all.begin() == ps_itr->prods_all.end() ) + return std::pair({{0, eosio::public_key{}}, 0}); + + if(ps_itr->is_org) { + //if(ps_itr->prods_l1.is_active && ps_itr->prods_l1.total_votes > 50000000000) { + if(ps_itr->prods_l1.is_active && ps_itr->prods_l1.total_votes > 0) { + return std::pair({{ps_itr->prods_l1.owner, ps_itr->prods_l1.producer_key}, ps_itr->prods_l1.location}); + } else { + _prodseq.modify(ps_itr, _self, [&](auto &row) { + row.is_org = false; + }); + } + } + + + double total_votes = 0; + bool is_find = false; + auto max = ps_itr->prods_all.begin(); + for( auto it = ps_itr->prods_all.begin(); it != ps_itr->prods_all.end(); it++ ) { + if(it->is_active && it->total_votes > total_votes) { + max = it; + total_votes = it->total_votes; + is_find = true; + } + } + + if(is_find) + return std::pair({{max->owner, max->producer_key}, max->location}); + + return std::pair({{0, eosio::public_key{}}, 0}); + } + +//##YTA-Change end: + + void system_contract::update_elected_producers( block_timestamp block_time ) { + _gstate.last_producer_schedule_update = block_time; + + auto idx = _producers.get_index(); + + std::vector< std::pair > top_producers; + top_producers.reserve(21); + + for ( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { + top_producers.emplace_back( std::pair({{it->owner, it->producer_key}, it->location}) ); + } + + + if ( top_producers.size() < _gstate.last_producer_schedule_size ) { + return; + } + + /// sort by producer name + std::sort( top_producers.begin(), top_producers.end() ); + + std::vector producers; + + producers.reserve(top_producers.size()); + for( const auto& item : top_producers ) + producers.push_back(item.first); + + bytes packed_schedule = pack(producers); + + + if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { + _gstate.last_producer_schedule_size = static_cast( top_producers.size() ); + } + } + + double stake2vote( int64_t staked ) { + /// TODO subtract 2080 brings the large numbers closer to this decade + //double weight = int64_t( (now() - (block_timestamp::block_timestamp_epoch / 1000)) / (seconds_per_day * 7) ) / double( 52 ); + //return double(staked) * std::pow( 2, weight ); + return double(staked); + } + /** + * @pre producers must be sorted from lowest to highest and must be registered and active + * @pre if proxy is set then no producers can be voted for + * @pre if proxy is set then proxy account must exist and be registered as a proxy + * @pre every listed producer or proxy must have been previously registered + * @pre voter must authorize this action + * @pre voter must have previously staked some EOS for voting + * @pre voter->staked must be up to date + * + * @post every producer previously voted for will have vote reduced by previous vote weight + * @post every producer newly voted for will have vote increased by new vote amount + * @post prior proxy will proxied_vote_weight decremented by previous vote weight + * @post new proxy will proxied_vote_weight incremented by new vote weight + * + * If voting for a proxy, the producer votes will not change until the proxy updates their own vote. + */ + void system_contract::voteproducer( const account_name voter_name, const account_name proxy, const std::vector& producers ) { + require_auth( voter_name ); + ///@@@@@@@@@@@@@@@@@@@@@ + eosio_assert(1 == 2, "can not vote now."); + return; + ///@@@@@@@@@@@@@@@@@@@@ + + update_votes( voter_name, proxy, producers, true ); + } + + void system_contract::update_votes( const account_name voter_name, const account_name proxy, const std::vector& producers, bool voting ) { + //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 { + //##YTA-Change start: + //eosio_assert( producers.size() <= 30, "attempt to vote for too many producers" ); + // One voter can only vote for one producer + eosio_assert( producers.size() <= 1, "attempt to vote for too many producers" ); + //##YTA-Change end: + for( size_t i = 1; i < producers.size(); ++i ) { + eosio_assert( producers[i-1] < producers[i], "producer votes must be unique and sorted" ); + } + } + + auto voter = _voters.find(voter_name); + eosio_assert( voter != _voters.end(), "user must stake before they can vote" ); /// staking creates voter object + eosio_assert( !proxy || !voter->is_proxy, "account registered as a proxy is not allowed to use a proxy" ); + + /** + * The first time someone votes we calculate and set last_vote_weight, since they cannot unstake until + * after total_activated_stake hits threshold, we can use last_vote_weight to determine that this is + * their first vote and should consider their stake activated. + */ + if( voter->last_vote_weight <= 0.0 ) { + _gstate.total_activated_stake += voter->staked; + if( _gstate.total_activated_stake >= min_activated_stake && _gstate.thresh_activated_stake_time == 0 ) { + _gstate.thresh_activated_stake_time = current_time(); + } + } + + auto new_vote_weight = stake2vote( voter->staked ); + if( voter->is_proxy ) { + new_vote_weight += voter->proxied_vote_weight; + } + + boost::container::flat_map > producer_deltas; + if ( voter->last_vote_weight > 0 ) { + if( voter->proxy ) { + auto old_proxy = _voters.find( voter->proxy ); + eosio_assert( old_proxy != _voters.end(), "old proxy not found" ); //data corruption + _voters.modify( old_proxy, 0, [&]( auto& vp ) { + vp.proxied_vote_weight -= voter->last_vote_weight; + }); + propagate_weight_change( *old_proxy ); + } else { + for( const auto& p : voter->producers ) { + auto& d = producer_deltas[p]; + d.first -= voter->last_vote_weight; + d.second = false; + } + } + } + + if( proxy ) { + auto new_proxy = _voters.find( proxy ); + eosio_assert( new_proxy != _voters.end(), "invalid proxy specified" ); //if ( !voting ) { data corruption } else { wrong vote } + eosio_assert( !voting || new_proxy->is_proxy, "proxy not found" ); + if ( new_vote_weight >= 0 ) { + _voters.modify( new_proxy, 0, [&]( auto& vp ) { + vp.proxied_vote_weight += new_vote_weight; + }); + propagate_weight_change( *new_proxy ); + } + } else { + if( new_vote_weight >= 0 ) { + for( const auto& p : producers ) { + auto& d = producer_deltas[p]; + d.first += new_vote_weight; + d.second = true; + } + } + } + + for( const auto& pd : producer_deltas ) { + double total_votes = 0; + auto pitr = _producers.find( pd.first ); + if( pitr != _producers.end() ) { + eosio_assert( !voting || pitr->active() || !pd.second.second /* not from new set */, "producer is not currently registered" ); + _producers.modify( pitr, 0, [&]( auto& p ) { + p.total_votes += pd.second.first; + if ( p.total_votes < 0 ) { // floating point arithmetics can give small negative numbers + p.total_votes = 0; + } + _gstate.total_producer_vote_weight += pd.second.first; + //eosio_assert( p.total_votes >= 0, "something bad happened" ); + total_votes = p.total_votes; + }); + } else { + eosio_assert( !pd.second.second /* not from new set */, "producer is not registered" ); //data corruption + } + //##YTA-Change start: + auto pitr2 = _producersext.find( pd.first ); + if( pitr2 != _producersext.end() ) { + //pitr2->seq_num + update_producers_seq_totalvotes(pitr2->seq_num, pd.first, total_votes); + } else { + eosio_assert( !pd.second.second /* not from new set */, "producer is not registered" ); //data corruption + } + //##YTA-Change end: + + + } + + _voters.modify( voter, 0, [&]( auto& av ) { + av.last_vote_weight = new_vote_weight; + av.producers = producers; + av.proxy = proxy; + }); + } + + /** + * An account marked as a proxy can vote with the weight of other accounts which + * have selected it as a proxy. Other accounts must refresh their voteproducer to + * update the proxy's weight. + * + * @param isproxy - true if proxy wishes to vote on behalf of others, false otherwise + * @pre proxy must have something staked (existing row in voters table) + * @pre new state must be different than current state + */ + void system_contract::regproxy( const account_name proxy, bool isproxy ) { + require_auth( proxy ); + + auto pitr = _voters.find(proxy); + if ( pitr != _voters.end() ) { + eosio_assert( isproxy != pitr->is_proxy, "action has no effect" ); + eosio_assert( !isproxy || !pitr->proxy, "account that uses a proxy is not allowed to become a proxy" ); + _voters.modify( pitr, 0, [&]( auto& p ) { + p.is_proxy = isproxy; + }); + propagate_weight_change( *pitr ); + } else { + _voters.emplace( proxy, [&]( auto& p ) { + p.owner = proxy; + p.is_proxy = isproxy; + }); + } + } + + void system_contract::propagate_weight_change( const voter_info& voter ) { + eosio_assert( voter.proxy == 0 || !voter.is_proxy, "account registered as a proxy is not allowed to use a proxy" ); + double new_weight = stake2vote( voter.staked ); + if ( voter.is_proxy ) { + new_weight += voter.proxied_vote_weight; + } + + /// don't propagate small changes (1 ~= epsilon) + if ( fabs( new_weight - voter.last_vote_weight ) > 1 ) { + if ( voter.proxy ) { + auto& proxy = _voters.get( voter.proxy, "proxy not found" ); //data corruption + _voters.modify( proxy, 0, [&]( auto& p ) { + p.proxied_vote_weight += new_weight - voter.last_vote_weight; + } + ); + propagate_weight_change( proxy ); + } else { + auto delta = new_weight - voter.last_vote_weight; + for ( auto acnt : voter.producers ) { + auto& pitr = _producers.get( acnt, "producer not found" ); //data corruption + _producers.modify( pitr, 0, [&]( auto& p ) { + p.total_votes += delta; + _gstate.total_producer_vote_weight += delta; + }); + } + } + } + _voters.modify( voter, 0, [&]( auto& v ) { + v.last_vote_weight = new_weight; + } + ); + } + +} /// namespace eosiosystem