diff --git a/libraries/plugins/rc/include/steem/plugins/rc/rc_config.hpp b/libraries/plugins/rc/include/steem/plugins/rc/rc_config.hpp index f5a59f7391..1fa3e30268 100644 --- a/libraries/plugins/rc/include/steem/plugins/rc/rc_config.hpp +++ b/libraries/plugins/rc/include/steem/plugins/rc/rc_config.hpp @@ -3,3 +3,4 @@ #define STEEM_RC_REGEN_TIME (60*60*24*5) #define STEEM_RC_MAX_OUTDEL_SLOTS 3 #define STEEM_RC_RECOVERY_SLOT_NUM 1 +#define STEEM_RC_MAX_OUTDEL 40 diff --git a/libraries/plugins/rc/include/steem/plugins/rc/rc_objects.hpp b/libraries/plugins/rc/include/steem/plugins/rc/rc_objects.hpp index faaf5475fb..3b8284fd80 100644 --- a/libraries/plugins/rc/include/steem/plugins/rc/rc_objects.hpp +++ b/libraries/plugins/rc/include/steem/plugins/rc/rc_objects.hpp @@ -89,6 +89,8 @@ class rc_account_object : public object< rc_account_object_type, rc_account_obje asset max_rc_creation_adjustment = asset( 0, VESTS_SYMBOL ); asset vests_delegated_to_pools = asset( 0, VESTS_SYMBOL ); + uint32_t out_delegations = 0; + // This is used for bug-catching, to match that the vesting shares in a // pre-op are equal to what they were at the last post-op. int64_t last_max_rc = 0; @@ -265,8 +267,8 @@ typedef multi_index_container< ordered_unique< tag< by_edge >, composite_key< rc_indel_edge_object, member< rc_indel_edge_object, account_name_type, &rc_indel_edge_object::from_account >, - member< rc_indel_edge_object, account_name_type, &rc_indel_edge_object::to_pool >, - const_mem_fun< rc_indel_edge_object, asset_symbol_type, &rc_indel_edge_object::get_asset_symbol > + const_mem_fun< rc_indel_edge_object, asset_symbol_type, &rc_indel_edge_object::get_asset_symbol >, + member< rc_indel_edge_object, account_name_type, &rc_indel_edge_object::to_pool > > > >, @@ -308,6 +310,7 @@ FC_REFLECT( steem::plugins::rc::rc_account_object, (rc_manabar) (max_rc_creation_adjustment) (vests_delegated_to_pools) + (out_delegations) (last_max_rc) ) CHAINBASE_SET_INDEX_TYPE( steem::plugins::rc::rc_account_object, steem::plugins::rc::rc_account_index ) diff --git a/libraries/plugins/rc/rc_operations.cpp b/libraries/plugins/rc/rc_operations.cpp index ec44bf7df7..cc287006f1 100644 --- a/libraries/plugins/rc/rc_operations.cpp +++ b/libraries/plugins/rc/rc_operations.cpp @@ -77,7 +77,12 @@ void delegate_to_pool_evaluator::do_apply( const delegate_to_pool_operation& op } rc_pool_manabar.regenerate_mana( rc_pool_manabar_params, now ); - const rc_indel_edge_object* edge = _db.find< rc_indel_edge_object, by_edge >( boost::make_tuple( op.from_account, op.to_pool, op.amount.symbol ) ); + const rc_indel_edge_object* edge = _db.find< rc_indel_edge_object, by_edge >( boost::make_tuple( op.from_account, op.amount.symbol, op.to_pool ) ); + + if( !edge ) + { + FC_ASSERT( from_rc_account.out_delegations <= STEEM_RC_MAX_OUTDEL, "Account already has ${n} delegations.", ("n", from_rc_account.out_delegations) ); + } int64_t old_max_rc = edge ? edge->amount.amount.value : 0; int64_t new_max_rc = op.amount.amount.value; @@ -134,6 +139,10 @@ void delegate_to_pool_evaluator::do_apply( const delegate_to_pool_operation& op e.amount = op.amount; } ); } + else if( op.amount.amount.value == 0 ) + { + _db.remove( *edge ); + } else { _db.modify< rc_indel_edge_object >( *edge, [&]( rc_indel_edge_object& e ) @@ -147,6 +156,15 @@ void delegate_to_pool_evaluator::do_apply( const delegate_to_pool_operation& op rca.rc_manabar = rc_account_manabar; if( op.amount.symbol == VESTS_SYMBOL ) rca.vests_delegated_to_pools += asset( delta_max_rc, VESTS_SYMBOL ); + + if( !edge ) + { + rca.out_delegations++; + } + else if( op.amount.amount.value == 0 ) + { + rca.out_delegations--; + } } ); } /* diff --git a/libraries/plugins/rc/rc_plugin.cpp b/libraries/plugins/rc/rc_plugin.cpp index 3963e848d9..21e8d467ca 100644 --- a/libraries/plugins/rc/rc_plugin.cpp +++ b/libraries/plugins/rc/rc_plugin.cpp @@ -835,6 +835,84 @@ struct post_apply_operation_visitor ) : _mod_accounts(ma), _db(db), _current_time(t), _current_block_number(b), _current_witness(w) {} + void update_outdel_overflow( const account_name_type& account, const asset& amount ) const + { + if( amount.symbol != VESTS_SYMBOL ) return; + + const auto& rc_acc = _db.get< rc_account_object, by_name >( account ); + + int64_t new_max_mana = get_maximum_rc( _db.get< account_object, by_name >( account ), rc_acc ); + int64_t pool_del_delta = 0; + int64_t returned_rcs = 0; + vector< const rc_indel_edge_object* > edges_to_remove; + + if( new_max_mana < rc_acc.max_rc_creation_adjustment.amount.value ) + { + int64_t needed_rcs = rc_acc.max_rc_creation_adjustment.amount.value - new_max_mana; + pool_del_delta = needed_rcs; + + const auto& rc_del_idx = _db.get_index< rc_indel_edge_index, by_edge >(); + auto rc_del_itr = rc_del_idx.lower_bound( boost::make_tuple( account, VESTS_SYMBOL ) ); + + while( needed_rcs > 0 && rc_del_itr != rc_del_idx.end() && rc_del_itr->from_account == account ) + { + int64_t edge_delta_rc = std::min( needed_rcs, rc_del_itr->amount.amount.value ); + + const auto& rc_pool = _db.get< rc_delegation_pool_object, by_account_symbol >( boost::make_tuple( rc_del_itr->to_pool, VESTS_SYMBOL ) ); + auto pool_manabar = rc_pool.rc_pool_manabar; + + if( pool_manabar.last_update_time < _db.head_block_time().sec_since_epoch() ) + { + manabar_params mbparams; + mbparams.max_mana = rc_pool.max_rc; + mbparams.regen_time = STEEM_RC_REGEN_TIME; + pool_manabar.regenerate_mana< true >( mbparams, _db.head_block_time() ); + } + + if( pool_manabar.current_mana > 0 ) + { + int64_t delta_pool_rc = std::min( pool_manabar.current_mana, edge_delta_rc ); + pool_manabar.current_mana -= delta_pool_rc; + returned_rcs += delta_pool_rc; + } + + needed_rcs -= edge_delta_rc; + + _db.modify( rc_pool, [&]( rc_delegation_pool_object& pool ) + { + pool.max_rc -= edge_delta_rc; + pool.rc_pool_manabar = pool_manabar; + }); + + if( rc_del_itr->amount.amount.value > edge_delta_rc ) + { + _db.modify( *rc_del_itr, [&]( rc_indel_edge_object& indel ) + { + indel.amount.amount.value -= edge_delta_rc; + }); + } + else + { + edges_to_remove.push_back( &(*rc_del_itr) ); + } + + ++rc_del_itr; + } + + for( const rc_indel_edge_object* edge_ptr : edges_to_remove ) + { + _db.remove( *edge_ptr ); + } + } + + _db.modify( rc_acc, [&]( rc_account_object& rca ) + { + rca.rc_manabar.current_mana += returned_rcs; + rca.vests_delegated_to_pools.amount.value -= pool_del_delta; + rca.out_delegations -= edges_to_remove.size(); + }); + } + void operator()( const account_create_operation& op )const { create_rc_account( _db, _current_time, op.new_account_name, op.fee ); @@ -882,6 +960,9 @@ struct post_apply_operation_visitor { _mod_accounts.emplace_back( op.delegator ); _mod_accounts.emplace_back( op.delegatee ); + + update_outdel_overflow( op.delegator, op.vesting_shares ); + update_outdel_overflow( op.delegatee, op.vesting_shares ); } void operator()( const author_reward_operation& op )const