From 7e33a8063949a206cd664cc298fae708b2609882 Mon Sep 17 00:00:00 2001 From: Anton Perkov Date: Thu, 17 May 2018 17:58:37 -0400 Subject: [PATCH] refund from net stake is not allowed to go to cpu stake and vice versa #3180 --- contracts/eosio.system/delegate_bandwidth.cpp | 81 +++++++++++-------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/contracts/eosio.system/delegate_bandwidth.cpp b/contracts/eosio.system/delegate_bandwidth.cpp index 6cffa61d0..e94c80754 100644 --- a/contracts/eosio.system/delegate_bandwidth.cpp +++ b/contracts/eosio.system/delegate_bandwidth.cpp @@ -63,12 +63,13 @@ namespace eosiosystem { struct refund_request { account_name owner; time request_time; - eosio::asset amount; + 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)(amount) ) + EOSLIB_SERIALIZE( refund_request, (owner)(request_time)(net_amount)(cpu_amount) ) }; /** @@ -223,10 +224,10 @@ namespace eosiosystem { } void system_contract::changebw( account_name from, account_name receiver, - asset stake_net_quantity, asset stake_cpu_quantity, bool transfer ) + const asset stake_net_delta, const asset stake_cpu_delta, bool transfer ) { require_auth( from ); - eosio_assert( stake_net_quantity != asset(0) || stake_cpu_quantity != asset(0), "should stake non-zero amount" ); + eosio_assert( stake_net_delta != asset(0) || stake_cpu_delta != asset(0), "should stake non-zero amount" ); account_name source_stake_from = from; if ( transfer ) { @@ -241,14 +242,14 @@ namespace eosiosystem { itr = del_tbl.emplace( from, [&]( auto& dbo ){ dbo.from = from; dbo.to = receiver; - dbo.net_weight = stake_net_quantity; - dbo.cpu_weight = stake_cpu_quantity; + 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_quantity; - dbo.cpu_weight += stake_cpu_quantity; + dbo.net_weight += stake_net_delta; + dbo.cpu_weight += stake_cpu_delta; }); } eosio_assert( asset(0) <= itr->net_weight, "insufficient staked net bandwidth" ); @@ -265,13 +266,13 @@ namespace eosiosystem { if( tot_itr == totals_tbl.end() ) { tot_itr = totals_tbl.emplace( from, [&]( auto& tot ) { tot.owner = receiver; - tot.net_weight = stake_net_quantity; - tot.cpu_weight = stake_cpu_quantity; + 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_quantity; - tot.cpu_weight += stake_cpu_quantity; + 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" ); @@ -284,46 +285,53 @@ namespace eosiosystem { } } // tot_itr can be invalid, should go out of scope - // transfer money or schedule a refund - asset total_update = stake_net_quantity + stake_cpu_quantity; - - if ( N(eosio) != source_stake_from ) { //for eosio transfer/refund doesn't make sense + // create refund or update from existing refund + if ( N(eosio) != 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 - asset update_balance = total_update; + auto net_balance = stake_net_delta; + auto cpu_balance = stake_cpu_delta; bool need_deferred_trx = false; - if ( req != refunds_tbl.end() ) { + if ( req != refunds_tbl.end() ) { //need to update refund refunds_tbl.modify( req, 0, [&]( refund_request& r ) { - r.amount -= update_balance; - if ( r.amount < asset(0) ){ - update_balance = -r.amount; - r.amount = asset(0); + r.net_amount -= net_balance; + if ( r.net_amount < asset(0) ) { + net_balance = -r.net_amount; + r.net_amount = asset(0); + } + r.cpu_amount -= cpu_balance; + if ( r.cpu_amount < asset(0) ){ + cpu_balance = -r.cpu_amount; + r.cpu_amount = asset(0); } r.request_time = now(); }); - eosio_assert( asset(0) <= req->amount, "negative refund amount" ); //should never happen + 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->amount == asset(0) ) { + 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 ( update_balance < asset(0) ) { + } else if ( net_balance < asset(0) && cpu_balance < asset(0) ) { //need to create refund refunds_tbl.emplace( from, [&]( refund_request& r ) { r.owner = from; - r.amount = -total_update; + 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 increases with no existing row in refunds_tbl -> nothing to do with refunds_tbl - - if ( asset(0) < update_balance ) { - INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {from,N(active)}, - { source_stake_from, N(eosio), asset(update_balance), std::string("stake bandwidth") } ); - } + } // else stake increase requested with no existing row in refunds_tbl -> nothing to do with refunds_tbl if ( need_deferred_trx ) { eosio::transaction out; @@ -333,10 +341,17 @@ namespace eosiosystem { } 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), {from,N(active)}, + { source_stake_from, N(eosio), 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 ) { @@ -393,7 +408,7 @@ namespace eosiosystem { // consecutive missed blocks. INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, - { N(eosio), req->owner, req->amount, std::string("unstake") } ); + { N(eosio), req->owner, req->net_amount + req->cpu_amount, std::string("unstake") } ); refunds_tbl.erase( req ); } -- GitLab