diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index cd295fff37..09994d90e7 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1097,19 +1097,19 @@ state database_api::get_state( string path )const _state.category_idx.trending.push_back(c.name); _state.categories[c.name] = c; } - auto recent_cat = get_recent_categories( "", 20 ); + auto recent_cat = get_recent_categories( "", 50 ); for( const auto& c : recent_cat ) { _state.category_idx.active.push_back(c.name); _state.categories[c.name] = c; } - auto active_cat = get_active_categories( "", 20 ); + auto active_cat = get_active_categories( "", 50 ); for( const auto& c : active_cat ) { _state.category_idx.active.push_back(c.name); _state.categories[c.name] = c; } - auto best_cat = get_best_categories( "", 20 ); + auto best_cat = get_best_categories( "", 50 ); for( const auto& c : best_cat ) { _state.category_idx.best.push_back(c.name); @@ -1218,7 +1218,7 @@ state database_api::get_state( string path )const _state.pow_queue = get_miner_queue(); } else if( part[0] == "trending" && part[1].size() ) { - auto trending_disc = get_discussions_in_category_by_total_pending_payout( part[1], "", "", 20 ); + auto trending_disc = get_discussions_in_category_by_total_pending_payout( part[1], "", "", 50 ); auto& didx = _state.discussion_idx[part[1]]; for( const auto& d : trending_disc ) { @@ -1229,7 +1229,7 @@ state database_api::get_state( string path )const } } else if( part[0] == "trending" || part[0] == "") { - auto trending_disc = get_discussions_by_total_pending_payout( "", "", 20 ); + auto trending_disc = get_discussions_by_total_pending_payout( "", "", 50 ); auto& didx = _state.discussion_idx[""]; for( const auto& d : trending_disc ) { auto key = d.author +"/" + d.permlink; @@ -1241,7 +1241,7 @@ state database_api::get_state( string path )const else if( part[0] == "best" && part[1] == "" ) { } else if( part[0] == "maturing" && part[1] == "" ) { - auto trending_disc = get_discussions_by_cashout_time( "", "", 20 ); + auto trending_disc = get_discussions_by_cashout_time( "", "", 50 ); auto& didx = _state.discussion_idx[""]; for( const auto& d : trending_disc ) { auto key = d.author +"/" + d.permlink; @@ -1251,7 +1251,7 @@ state database_api::get_state( string path )const } } else if( part[0] == "maturing" ) { - auto trending_disc = get_discussions_in_category_by_cashout_time( part[1], "", "", 20 ); + auto trending_disc = get_discussions_in_category_by_cashout_time( part[1], "", "", 50 ); auto& didx = _state.discussion_idx[part[1]]; for( const auto& d : trending_disc ) { auto key = d.author +"/" + d.permlink; @@ -1261,7 +1261,7 @@ state database_api::get_state( string path )const } } else if( part[0] == "recent" && part[1] == "") { - auto trending_disc = get_discussions_by_last_update( "", "", 20 ); + auto trending_disc = get_discussions_by_last_update( "", "", 50 ); auto& didx = _state.discussion_idx[""]; for( const auto& d : trending_disc ) { auto key = d.author +"/" + d.permlink; @@ -1270,7 +1270,7 @@ state database_api::get_state( string path )const _state.content[key] = std::move(d); } } else if( part[0] == "recent" ) { - auto trending_disc = get_discussions_in_category_by_last_update( part[1], "", "", 20 ); + auto trending_disc = get_discussions_in_category_by_last_update( part[1], "", "", 50 ); auto& didx = _state.discussion_idx[part[1]]; for( const auto& d : trending_disc ) { auto key = d.author +"/" + d.permlink; diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index a0b5c38f75..3824bf9c24 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -866,7 +866,7 @@ try { props.total_vesting_shares += new_vesting; }); - adjust_witness_votes( to_account, new_vesting.amount ); + adjust_proxied_witness_votes( to_account, new_vesting.amount ); return new_vesting; } FC_CAPTURE_AND_RETHROW( (to_account.name)(steem) ) } @@ -998,7 +998,7 @@ void database::update_witness_schedule() { if( (head_block_num() % STEEMIT_MAX_MINERS) == 0 ) //wso.next_shuffle_block_num ) { - if( has_hardfork(STEEMIT_HARDFORK_4) ) { + if( has_hardfork(STEEMIT_HARDFORK_0_4_0) ) { update_witness_schedule4(); return; } @@ -1045,7 +1045,7 @@ void database::update_witness_schedule() new_virtual_time = fc::uint128(); /// this witness will produce again here - if( has_hardfork( STEEMIT_HARDFORK_2 ) ) + if( has_hardfork( STEEMIT_HARDFORK_0_2_0 ) ) wo.virtual_scheduled_time += VIRTUAL_SCHEDULE_LAP_LENGTH2 / (wo.votes.value+1); else wo.virtual_scheduled_time += VIRTUAL_SCHEDULE_LAP_LENGTH / (wo.votes.value+1); @@ -1054,7 +1054,7 @@ void database::update_witness_schedule() } /* TODO: delete this if we can reindex without it through HF4 */ - if( !has_hardfork( STEEMIT_HARDFORK_4 ) ) { + if( !has_hardfork( STEEMIT_HARDFORK_0_4_0 ) ) { while( sitr != schedule_idx.end() && sitr->pow_worker ) { modify( *sitr, [&]( witness_object& wo ) { wo.virtual_last_update = new_virtual_time; @@ -1165,7 +1165,7 @@ void database::update_median_witness_props() { }); } -void database::adjust_witness_votes( const account_object& a, share_type delta, int depth ) { +void database::adjust_proxied_witness_votes( const account_object& a, share_type delta, int depth ) { if( a.proxy != STEEMIT_PROXY_TO_SELF_ACCOUNT ) { const auto& proxy = get_account( a.proxy ); @@ -1177,7 +1177,7 @@ void database::adjust_witness_votes( const account_object& a, share_type delta, if( depth > STEEMIT_MAX_PROXY_RECURSION_DEPTH ) return; - adjust_witness_votes( proxy, delta, depth + 1 ); + adjust_proxied_witness_votes( proxy, delta, depth + 1 ); } else { const auto& vidx = get_index_type().indices().get(); @@ -1200,13 +1200,13 @@ void database::adjust_witness_vote( const witness_object& witness, share_type de w.votes += delta; FC_ASSERT( w.votes <= get_dynamic_global_properties().total_vesting_shares.amount, "", ("w.votes", w.votes)("props",get_dynamic_global_properties().total_vesting_shares) ); - if( has_hardfork( STEEMIT_HARDFORK_2 ) ) + if( has_hardfork( STEEMIT_HARDFORK_0_2_0 ) ) w.virtual_scheduled_time = w.virtual_last_update + (VIRTUAL_SCHEDULE_LAP_LENGTH2 - w.virtual_position)/(w.votes.value+1); else w.virtual_scheduled_time = w.virtual_last_update + (VIRTUAL_SCHEDULE_LAP_LENGTH - w.virtual_position)/(w.votes.value+1); /** witnesses with a low number of votes could overflow the time field and end up with a scheduled time in the past */ - if( has_hardfork( STEEMIT_HARDFORK_4 ) ) { + if( has_hardfork( STEEMIT_HARDFORK_0_4_0 ) ) { if( w.virtual_scheduled_time < wso.current_virtual_time ) w.virtual_scheduled_time = fc::uint128::max_value(); } @@ -1297,7 +1297,7 @@ void database::process_vesting_withdrawals() { }); if( withdrawn_vesting > 0 ) - adjust_witness_votes( cur, -withdrawn_vesting ); + adjust_proxied_witness_votes( cur, -withdrawn_vesting ); } } @@ -1375,11 +1375,15 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar auto itr = cvidx.lower_bound( boost::make_tuple( c.id, uint64_t(-1), account_id_type() ) ); auto end = cvidx.lower_bound( boost::make_tuple( c.id, uint64_t(0), account_id_type() ) ); while( itr != end ) { + // TODO: Add minimum curation pay limit u256 weight( itr->weight ); auto claim = static_cast((max_rewards.value * weight) / total_weight); - unclaimed_rewards -= claim; - auto reward = create_vesting( itr->voter(*this), asset( claim, STEEM_SYMBOL ) ); - push_applied_operation( curate_reward_operation( itr->voter(*this).name, reward, c.author, c.permlink ) ); + if( claim > 1 ) // min_amt is non-zero satoshis + { + unclaimed_rewards -= claim; + auto reward = create_vesting( itr->voter(*this), asset( claim, STEEM_SYMBOL ) ); + push_applied_operation( curate_reward_operation( itr->voter(*this).name, reward, c.author, c.permlink ) ); + } ++itr; } if( max_rewards.value - unclaimed_rewards.value ) @@ -1446,6 +1450,7 @@ void database::process_comment_cashout() { if( c.net_rshares > 0 ) c.net_rshares = 0; c.abs_rshares = 0; + c.total_vote_weight = 0; c.cashout_time = fc::time_point_sec::maximum(); }); @@ -1647,7 +1652,6 @@ share_type database::claim_rshare_reward( share_type rshares ) { payout = 0; modify( props, [&]( dynamic_global_property_object& p ){ - p.total_reward_shares2 -= fc::uint128_t( rshares.value ) * rshares.value; p.total_reward_fund_steem.amount -= payout; }); @@ -1730,6 +1734,7 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); //Implementation object indexes add_index< primary_index >(); @@ -1867,7 +1872,7 @@ void database::apply_block( const signed_block& next_block, uint32_t skip ) } ); /// check invariants - if( !( skip & skip_validate_invariants ) ) + //if( !( skip & skip_validate_invariants ) ) validate_invariants(); } @@ -2163,7 +2168,7 @@ void database::update_global_dynamic_data( const signed_block& b ) dgp.current_reserve_ratio++; } - if( has_hardfork( STEEMIT_HARDFORK_2 ) && dgp.current_reserve_ratio > STEEMIT_MAX_RESERVE_RATIO ) + if( has_hardfork( STEEMIT_HARDFORK_0_2_0 ) && dgp.current_reserve_ratio > STEEMIT_MAX_RESERVE_RATIO ) dgp.current_reserve_ratio = STEEMIT_MAX_RESERVE_RATIO; } dgp.max_virtual_bandwidth = (dgp.maximum_block_size * dgp.current_reserve_ratio * @@ -2503,17 +2508,17 @@ asset database::get_balance( const account_object& a, asset_symbol_type symbol ) void database::init_hardforks() { _hardfork_times[ 0 ] = fc::time_point_sec( STEEMIT_GENESIS_TIME ); - FC_ASSERT( STEEMIT_HARDFORK_1 == 1, "Invalid hardfork configuration" ); - _hardfork_times[ STEEMIT_HARDFORK_1 ] = fc::time_point_sec( STEEMIT_HARDFORK_1_TIME ); - FC_ASSERT( STEEMIT_HARDFORK_2 == 2, "Invlaid hardfork configuration" ); - _hardfork_times[ STEEMIT_HARDFORK_2 ] = fc::time_point_sec( STEEMIT_HARDFORK_2_TIME ); - FC_ASSERT( STEEMIT_HARDFORK_3 == 3, "Invalid hardfork configuration" ); - _hardfork_times[ STEEMIT_HARDFORK_3 ] = fc::time_point_sec( STEEMIT_HARDFORK_3_TIME ); - FC_ASSERT( STEEMIT_HARDFORK_4 == 4, "Invalid hardfork configuration" ); - _hardfork_times[ STEEMIT_HARDFORK_4 ] = fc::time_point_sec( STEEMIT_HARDFORK_4_TIME ); + FC_ASSERT( STEEMIT_HARDFORK_0_1_0 == 1, "Invalid hardfork configuration" ); + _hardfork_times[ STEEMIT_HARDFORK_0_1_0 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_1_0_TIME ); + FC_ASSERT( STEEMIT_HARDFORK_0_2_0 == 2, "Invlaid hardfork configuration" ); + _hardfork_times[ STEEMIT_HARDFORK_0_2_0 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_2_0_TIME ); + FC_ASSERT( STEEMIT_HARDFORK_0_3_0 == 3, "Invalid hardfork configuration" ); + _hardfork_times[ STEEMIT_HARDFORK_0_3_0 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_3_0_TIME ); + FC_ASSERT( STEEMIT_HARDFORK_0_4_0 == 4, "Invalid hardfork configuration" ); + _hardfork_times[ STEEMIT_HARDFORK_0_4_0 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_4_0_TIME ); const auto& hardforks = hardfork_property_id_type()( *this ); - FC_ASSERT( hardforks.last_hardfork <= STEEMIT_NUM_HARDFORKS, "Chain knows of more hardforks than configuration" ); + FC_ASSERT( hardforks.last_hardfork <= STEEMIT_NUM_HARDFORKS, "Chain knows of more hardforks than configuration", ("hardforks.last_hardfork",hardforks.last_hardfork)("STEEMIT_NUM_HARDFORKS",STEEMIT_NUM_HARDFORKS) ); if( hardforks.last_hardfork >= 0 ) FC_ASSERT( _hardfork_times[ hardforks.last_hardfork - 1 ] <= head_block_time(), "Configuration has future hardfork set that chain has already applied." ); if( hardforks.last_hardfork + 1 < STEEMIT_NUM_HARDFORKS ) @@ -2546,19 +2551,12 @@ void database::process_hardforks() // If there are upcoming hardforks and the next one is later, do nothing const auto& hardforks = hardfork_property_id_type()( *this ); - // If we have applied the last known hardfork - if( hardforks.last_hardfork == STEEMIT_NUM_HARDFORKS ) - return; - - // If the next hardfork time is in the future - if( _hardfork_times[ hardforks.last_hardfork + 1 ] > head_block_time() ) - return; - - while( _hardfork_times[ hardforks.last_hardfork + 1 ] <= head_block_time() ) + while( hardforks.last_hardfork < STEEMIT_NUM_HARDFORKS + && _hardfork_times[ hardforks.last_hardfork + 1 ] <= head_block_time() ) { switch( hardforks.last_hardfork + 1) { - case STEEMIT_HARDFORK_1: + case STEEMIT_HARDFORK_0_1_0: elog( "HARDFORK 1" ); perform_vesting_share_split( 1000000 ); #ifdef IS_TEST_NET @@ -2572,15 +2570,15 @@ void database::process_hardforks() break; #endif break; - case STEEMIT_HARDFORK_2: + case STEEMIT_HARDFORK_0_2_0: elog( "HARDFORK 2" ); retally_witness_votes(); break; - case STEEMIT_HARDFORK_3: + case STEEMIT_HARDFORK_0_3_0: elog( "HARDFORK 3" ); retally_witness_votes(); break; - case STEEMIT_HARDFORK_4: + case STEEMIT_HARDFORK_0_4_0: elog( "HARDFORK 4" ); reset_virtual_schedule_time(); break; @@ -2692,10 +2690,10 @@ void database::validate_invariants()const total_supply += gpo.total_vesting_fund_steem + gpo.total_reward_fund_steem; - FC_ASSERT( gpo.current_supply.amount.value == total_supply.amount.value ); - FC_ASSERT( gpo.current_sbd_supply.amount.value == total_sbd.amount.value ); - FC_ASSERT( gpo.total_vesting_shares == total_vesting ); - FC_ASSERT( gpo.total_vesting_shares.amount == total_vsf_votes, "", ("total_vsf_votes",total_vsf_votes)("total_vesting_shares",gpo.total_vesting_shares) ); + FC_ASSERT( gpo.current_supply == total_supply, "", ("gpo.current_supply",gpo.current_supply)("total_supply",total_supply) ); + FC_ASSERT( gpo.current_sbd_supply == total_sbd, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("total_sbd",total_sbd) ); + FC_ASSERT( gpo.total_vesting_shares == total_vesting, "", ("gpo.total_vesting_shares",gpo.total_vesting_shares)("total_vesting",total_vesting) ); + FC_ASSERT( gpo.total_vesting_shares.amount == total_vsf_votes, "", ("total_vesting_shares",gpo.total_vesting_shares)("total_vsf_votes",total_vsf_votes) ); FC_ASSERT( gpo.total_reward_shares2 == total_rshares2, "", ("gpo.total",gpo.total_reward_shares2)("check.total",total_rshares2)("delta",gpo.total_reward_shares2-total_rshares2)); FC_ASSERT( total_rshares2 == total_children_rshares2, "", ("total_rshares2", total_rshares2)("total_children_rshares2",total_children_rshares2)); @@ -2786,24 +2784,16 @@ void database::retally_witness_votes() // Apply all existing votes by account for( auto itr = account_idx.begin(); itr != account_idx.end(); itr++ ) { - const witness_schedule_object& wso = witness_schedule_id_type()(*this); - const auto& a = *itr; + if( itr->proxy != STEEMIT_PROXY_TO_SELF_ACCOUNT ) continue; - const auto& vidx = get_index_type().indices().get(); - auto vitr = vidx.lower_bound( boost::make_tuple( a.get_id(), witness_id_type() ) ); - while( vitr != vidx.end() && vitr->account == a.get_id() ) { - modify( vitr->witness(*this), [&]( witness_object& w ){ - - auto delta_pos = w.votes.value * (wso.current_virtual_time - w.virtual_last_update); - w.virtual_position += delta_pos; - - w.virtual_last_update = wso.current_virtual_time; - w.votes += a.witness_vote_weight(); + const auto& a = *itr; - w.virtual_scheduled_time = w.virtual_last_update + (VIRTUAL_SCHEDULE_LAP_LENGTH2 - w.virtual_position)/(w.votes.value+1); - }); - ++vitr; - } + const auto& vidx = get_index_type().indices().get(); + auto wit_itr = vidx.lower_bound( boost::make_tuple( a.get_id(), witness_id_type() ) ); + while( wit_itr != vidx.end() && wit_itr->account == a.get_id() ) { + adjust_witness_vote( wit_itr->witness(*this), a.witness_vote_weight() ); + ++wit_itr; + } } } diff --git a/libraries/chain/hardfork.d/0_1_0.hf b/libraries/chain/hardfork.d/0_1_0.hf new file mode 100644 index 0000000000..77fd1ba94e --- /dev/null +++ b/libraries/chain/hardfork.d/0_1_0.hf @@ -0,0 +1,5 @@ +#ifndef STEEMIT_HARDFORK_0_1_0 +#define STEEMIT_HARDFORK_0_1_0 1 +// 4/25/2016 17:30:00 GMT +#define STEEMIT_HARDFORK_0_1_0_TIME 1461605400 +#endif diff --git a/libraries/chain/hardfork.d/0_2_0.hf b/libraries/chain/hardfork.d/0_2_0.hf new file mode 100644 index 0000000000..db3a9eccad --- /dev/null +++ b/libraries/chain/hardfork.d/0_2_0.hf @@ -0,0 +1,5 @@ +#ifndef STEEMIT_HARDFORK_0_2_0 +#define STEEMIT_HARDFORK_0_2_0 2 +// Tue, 26 Apr 2016 18:00:00 GMT +#define STEEMIT_HARDFORK_0_2_0_TIME 1461693600 +#endif diff --git a/libraries/chain/hardfork.d/0_3_0.hf b/libraries/chain/hardfork.d/0_3_0.hf new file mode 100644 index 0000000000..4cd21878a0 --- /dev/null +++ b/libraries/chain/hardfork.d/0_3_0.hf @@ -0,0 +1,5 @@ +#ifndef STEEMIT_HARDFORK_0_3_0 +#define STEEMIT_HARDFORK_0_3_0 3 +// 4/27/2016 13:00:00 GMT +#define STEEMIT_HARDFORK_0_3_0_TIME 1461762000 +#endif diff --git a/libraries/chain/hardfork.d/0_4_0.hf b/libraries/chain/hardfork.d/0_4_0.hf new file mode 100644 index 0000000000..7649949d84 --- /dev/null +++ b/libraries/chain/hardfork.d/0_4_0.hf @@ -0,0 +1,4 @@ +#ifndef STEEMIT_HARDFORK_0_4_0 +#define STEEMIT_HARDFORK_0_4_0 4 +#define STEEMIT_HARDFORK_0_4_0_TIME 1462028400 +#endif diff --git a/libraries/chain/hardfork.d/1.hf b/libraries/chain/hardfork.d/1.hf deleted file mode 100644 index dc9210dac0..0000000000 --- a/libraries/chain/hardfork.d/1.hf +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef STEEMIT_HARDFORK_1 -#define STEEMIT_HARDFORK_1 1 -// 4/25/2016 17:30:00 GMT -#define STEEMIT_HARDFORK_1_TIME 1461605400 -#endif diff --git a/libraries/chain/hardfork.d/2.hf b/libraries/chain/hardfork.d/2.hf deleted file mode 100644 index b7e45b6ab4..0000000000 --- a/libraries/chain/hardfork.d/2.hf +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef STEEMIT_HARDFORK_2 -#define STEEMIT_HARDFORK_2 2 -// Tue, 26 Apr 2016 18:00:00 GMT -#define STEEMIT_HARDFORK_2_TIME 1461693600 -#endif diff --git a/libraries/chain/hardfork.d/3.hf b/libraries/chain/hardfork.d/3.hf deleted file mode 100644 index 0b5e925891..0000000000 --- a/libraries/chain/hardfork.d/3.hf +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef STEEMIT_HARDFORK_3 -#define STEEMIT_HARDFORK_3 3 -// 4/27/2016 13:00:00 GMT -#define STEEMIT_HARDFORK_3_TIME 1461762000 -#endif diff --git a/libraries/chain/hardfork.d/4.hf b/libraries/chain/hardfork.d/4.hf deleted file mode 100644 index 1ac9484889..0000000000 --- a/libraries/chain/hardfork.d/4.hf +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef STEEMIT_HARDFORK_4 -#define STEEMIT_HARDFORK_4 4 -#define STEEMIT_HARDFORK_4_TIME 1462028400 -#endif diff --git a/libraries/chain/include/steemit/chain/account_object.hpp b/libraries/chain/include/steemit/chain/account_object.hpp index 69141c89ac..36c02abc80 100644 --- a/libraries/chain/include/steemit/chain/account_object.hpp +++ b/libraries/chain/include/steemit/chain/account_object.hpp @@ -30,6 +30,7 @@ namespace steemit { namespace chain { bool mined = true; uint32_t comment_count = 0; uint32_t lifetime_vote_count = 0; + uint32_t post_count = 0; uint16_t voting_power = STEEMIT_100_PERCENT; ///< current voting power of this account, it falls after every vote time_point_sec last_vote_time; ///< used to increase the voting power of this account the longer it goes without voting. @@ -116,7 +117,14 @@ namespace steemit { namespace chain { struct by_name; struct by_proxy; + struct by_last_post; struct by_next_vesting_withdrawal; + struct by_steem_balance; + struct by_smp_balance; + struct by_smd_balance; + struct by_post_count; + struct by_vote_count; + /** * @ingroup object_index */ @@ -138,6 +146,48 @@ namespace steemit { namespace chain { member, member > /// composite key by_next_vesting_withdrawal + >, + ordered_unique< tag< by_last_post >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< time_point_sec >, std::less< object_id_type > > + >, + ordered_unique< tag< by_steem_balance >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< asset >, std::less< object_id_type > > + >, + ordered_unique< tag< by_smp_balance >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< asset >, std::less< object_id_type > > + >, + ordered_unique< tag< by_smd_balance >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< asset >, std::less< object_id_type > > + >, + ordered_unique< tag< by_post_count >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< uint32_t >, std::less< object_id_type > > + >, + ordered_unique< tag< by_vote_count >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< uint32_t >, std::less< object_id_type > > > > > account_multi_index_type; @@ -148,7 +198,7 @@ namespace steemit { namespace chain { FC_REFLECT_DERIVED( steemit::chain::account_object, (graphene::db::object), (name)(owner)(active)(posting)(memo_key)(json_metadata)(proxy) - (created)(mined)(comment_count)(lifetime_vote_count)(voting_power)(last_vote_time) + (created)(mined)(comment_count)(lifetime_vote_count)(post_count)(voting_power)(last_vote_time) (balance) (sbd_balance)(sbd_seconds)(sbd_seconds_last_update)(sbd_last_interest_payment) (vesting_shares)(vesting_withdraw_rate)(next_vesting_withdrawal)(withdrawn)(to_withdraw) diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index 7e296ac28b..1084c91ab4 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -101,6 +101,25 @@ namespace steemit { namespace chain { /** tracks the total payout this comment has received over time, measured in SBD */ asset total_payout_value = asset(0, SBD_SYMBOL); + + /** ID of stats object used for additional indicies on comment */ + comment_stats_id_type stats; + }; + + /** + * Because boost::multi_index has a limit on the number of simultainous indicies the comment + * object has to move some indicies to this helper class. + */ + class comment_stats_object : public abstract_object { + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_comment_stats_object_type; + + comment_id_type comment_id; + comment_id_type parent_comment_id; + category_id_type category_id; + account_id_type author_id; + int32_t net_votes = 0; }; @@ -148,6 +167,36 @@ namespace steemit { namespace chain { > > comment_vote_multi_index_type; + struct by_comment_id; + struct by_net_votes; + struct by_net_votes_in_category; + typedef multi_index_container< + comment_stats_object, + indexed_by< + ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >, + ordered_unique< tag< by_comment_id >, member< comment_stats_object, comment_id_type, &comment_stats_object::comment_id > >, + ordered_unique< tag< by_net_votes >, + composite_key< comment_stats_object, + member< comment_stats_object, comment_id_type, &comment_stats_object::parent_comment_id>, + member< comment_stats_object, int32_t, &comment_stats_object::net_votes>, + member< comment_stats_object, comment_id_type, &comment_stats_object::comment_id> + >, + composite_key_compare< std::less< comment_id_type >, std::greater< int32_t >, std::less > + >, + ordered_unique< tag< by_net_votes_in_category >, + composite_key< comment_stats_object, + member< comment_stats_object, category_id_type, &comment_stats_object::category_id>, + member< comment_stats_object, comment_id_type, &comment_stats_object::parent_comment_id>, + member< comment_stats_object, int32_t, &comment_stats_object::net_votes>, + member< comment_stats_object, comment_id_type, &comment_stats_object::comment_id> + >, + composite_key_compare< std::less, std::less< comment_id_type >, std::greater< int32_t >, std::less > + > + > + > comment_stats_multi_index_type; + + + struct by_permlink; @@ -178,6 +227,7 @@ namespace steemit { namespace chain { struct by_cashout_time_in_category; struct by_blog; /// author, parent, parent_author (aka topic), created (greater), permlink struct by_blog_category; /// author, parent, parent_author (aka topic), created (greater), permlink + /** * @ingroup object_index */ @@ -344,9 +394,10 @@ namespace steemit { namespace chain { > > comment_multi_index_type; - typedef generic_index< comment_object, comment_multi_index_type > comment_index; - typedef generic_index< comment_vote_object, comment_vote_multi_index_type > comment_vote_index; - typedef generic_index< category_object, category_multi_index_type > category_index; + typedef generic_index< comment_object, comment_multi_index_type > comment_index; + typedef generic_index< comment_vote_object, comment_vote_multi_index_type > comment_vote_index; + typedef generic_index< comment_stats_object,comment_stats_multi_index_type > comment_stats_index; + typedef generic_index< category_object, category_multi_index_type > category_index; } } // steemit::chain FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), @@ -354,9 +405,17 @@ FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), (category)(parent_author)(parent_permlink) (title)(body)(json_metadata)(last_update)(created) (depth)(children)(children_rshares2) - (net_rshares)(abs_rshares)(cashout_time)(total_vote_weight)(total_payout_value) ) + (net_rshares)(abs_rshares)(cashout_time)(total_vote_weight)(total_payout_value)(stats) ) FC_REFLECT_DERIVED( steemit::chain::comment_vote_object, (graphene::db::object), (voter)(comment)(weight) ) FC_REFLECT_DERIVED( steemit::chain::category_object, (graphene::db::object), (name)(abs_rshares)(total_payouts)(discussions)(last_update) ); + +FC_REFLECT_DERIVED( steemit::chain::comment_stats_object, (graphene::db::object), + (comment_id) + (parent_comment_id) + (category_id) + (author_id) + (net_votes) + ) diff --git a/libraries/chain/include/steemit/chain/database.hpp b/libraries/chain/include/steemit/chain/database.hpp index 0c6f132595..d8c5c953bc 100644 --- a/libraries/chain/include/steemit/chain/database.hpp +++ b/libraries/chain/include/steemit/chain/database.hpp @@ -243,14 +243,14 @@ namespace steemit { namespace chain { asset get_balance( const string& aname, asset_symbol_type symbol )const { return get_balance( get_account(aname), symbol ); } /** this updates the votes for all witnesses as a result of account VESTS changing */ - void adjust_witness_votes( const account_object& a, share_type delta, int depth = 0 ); + void adjust_proxied_witness_votes( const account_object& a, share_type delta, int depth = 0 ); /** this updates the vote of a single witness as a result of a vote being added or removed*/ void adjust_witness_vote( const witness_object& obj, share_type delta ); /** clears all vote records for a particular account but does not update the * witness vote totals. Vote totals should be updated first via a call to - * adjust_witness_votes( a, -a.witness_vote_weight() ) + * adjust_proxied_witness_votes( a, -a.witness_vote_weight() ) */ void clear_witness_votes( const account_object& a ); void process_vesting_withdrawals(); diff --git a/libraries/chain/include/steemit/chain/protocol/types.hpp b/libraries/chain/include/steemit/chain/protocol/types.hpp index 0239002c37..c89d920f71 100644 --- a/libraries/chain/include/steemit/chain/protocol/types.hpp +++ b/libraries/chain/include/steemit/chain/protocol/types.hpp @@ -102,6 +102,7 @@ namespace steemit { namespace chain { impl_chain_property_object_type, impl_witness_schedule_object_type, impl_comment_object_type, + impl_comment_stats_object_type, impl_comment_vote_object_type, impl_vote_object_type, impl_witness_vote_object_type, @@ -120,6 +121,7 @@ namespace steemit { namespace chain { class comment_object; class category_object; class comment_vote_object; + class comment_stats_object; class vote_object; class witness_vote_object; class account_object; @@ -139,6 +141,7 @@ namespace steemit { namespace chain { typedef object_id< implementation_ids, impl_operation_object_type, operation_object> operation_id_type; typedef object_id< implementation_ids, impl_account_history_object_type, account_history_object> account_history_id_type; typedef object_id< implementation_ids, impl_comment_object_type, comment_object> comment_id_type; + typedef object_id< implementation_ids, impl_comment_stats_object_type, comment_stats_object> comment_stats_id_type; typedef object_id< implementation_ids, impl_category_object_type, category_object> category_id_type; typedef object_id< implementation_ids, impl_comment_vote_object_type, comment_vote_object> comment_vote_id_type; typedef object_id< implementation_ids, impl_vote_object_type, vote_object> vote_id_type; @@ -266,6 +269,7 @@ FC_REFLECT_ENUM( steemit::chain::impl_object_type, (impl_chain_property_object_type) (impl_witness_schedule_object_type) (impl_comment_object_type) + (impl_comment_stats_object_type) (impl_category_object_type) (impl_comment_vote_object_type) (impl_vote_object_type) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 345e11513e..a1d48d5838 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -36,7 +36,7 @@ void witness_update_evaluator::do_apply( const witness_update_operation& o ) { const auto& witness_account = db().get_account( o.owner ); - if ( db().has_hardfork( STEEMIT_HARDFORK_1 ) ) FC_ASSERT( o.url.size() <= STEEMIT_MAX_WITNESS_URL_LENGTH ); + if ( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) FC_ASSERT( o.url.size() <= STEEMIT_MAX_WITNESS_URL_LENGTH ); const auto& by_witness_name_idx = db().get_index_type< witness_index >().indices().get< by_name >(); auto wit_itr = by_witness_name_idx.find( o.owner ); @@ -68,7 +68,7 @@ void account_create_evaluator::do_apply( const account_create_operation& o ) FC_ASSERT( creator.balance >= o.fee, "Isufficient balance to create account", ( "creator.balance", creator.balance )( "required", o.fee ) ); - if( db().has_hardfork( STEEMIT_HARDFORK_1 ) ) { + if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) { const witness_schedule_object& wso = db().get_witness_schedule_object(); FC_ASSERT( o.fee >= wso.median_props.account_creation_fee, "Insufficient Fee: ${f} required, ${p} provided", ("f", wso.median_props.account_creation_fee) @@ -102,7 +102,7 @@ void account_create_evaluator::do_apply( const account_create_operation& o ) void account_update_evaluator::do_apply( const account_update_operation& o ) { - if( db().has_hardfork( STEEMIT_HARDFORK_1 ) ) FC_ASSERT( o.account != STEEMIT_TEMP_ACCOUNT ); + if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) FC_ASSERT( o.account != STEEMIT_TEMP_ACCOUNT ); db().modify( db().get_account( o.account ), [&]( account_object& acc ) { @@ -139,14 +139,15 @@ void comment_evaluator::do_apply( const comment_operation& o ) if ( itr == by_permlink_idx.end() ) { - FC_ASSERT( (now - auth.last_post) > fc::seconds(60), "You may only post once per minute" ); + FC_ASSERT( (now - auth.last_post) > fc::seconds(60), "You may only post once per minute", ("now",now)("auth.last_post",auth.last_post) ); db().modify( auth, [&]( account_object& a ) { a.last_post = now; + a.post_count++; }); const auto& new_comment = db().create< comment_object >( [&]( comment_object& com ) { - if( db().has_hardfork( STEEMIT_HARDFORK_1 ) ) + if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) { validate_permlink( o.parent_permlink ); validate_permlink( o.permlink ); @@ -178,6 +179,7 @@ void comment_evaluator::do_apply( const comment_operation& o ) com.json_metadata = o.json_metadata; #endif }); + const category_object* cat = db().find_category( new_comment.category ); if( !cat ) { cat = &db().create( [&]( category_object& c ){ @@ -192,6 +194,16 @@ void comment_evaluator::do_apply( const comment_operation& o ) }); } + const auto& new_comment_stats = db().create( [&]( comment_stats_object& cso ){ + cso.comment_id = new_comment.id; + if( parent ) + cso.parent_comment_id = parent->id; + cso.category_id = cat->id; + cso.author_id = auth.get_id(); + }); + + db().modify( new_comment, [&]( comment_object& co ) { co.stats = new_comment_stats.id; } ); + id = new_comment.id; /// this loop can be skiped for validate-only nodes as it is merely gathering stats for indicies @@ -232,9 +244,15 @@ void comment_evaluator::do_apply( const comment_operation& o ) } com.last_update = db().head_block_time(); - com.net_rshares = std::min( com.net_rshares, share_type(0) ); - com.abs_rshares = 0; - com.cashout_time = com.last_update + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS); + + if( o.title.size() + o.body.size() ) + { + if( com.net_rshares > 0 ) + com.net_rshares = 0; + com.abs_rshares = 0; + com.total_vote_weight = 0; + com.cashout_time = com.last_update + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS); + } #ifndef IS_LOW_MEM com.title = o.title; @@ -263,6 +281,17 @@ void comment_evaluator::do_apply( const comment_operation& o ) #endif }); + + if( o.title.size() + o.body.size() ) + { + const auto& vote_idx = db().get_index_type().indices().get(); + auto vote_itr = vote_idx.lower_bound( comment_id_type(comment.id) ); + while( vote_itr != vote_idx.end() && vote_itr->comment == comment.id ) { + const auto& cur_vote = *vote_itr; + ++vote_itr; + db().remove(cur_vote); + } + } } // end EDIT case } FC_CAPTURE_LOG_AND_RETHROW( (o) ) } @@ -307,11 +336,11 @@ void transfer_evaluator::do_apply( const transfer_operation& o ) a.last_bandwidth_update = now; */ - db().adjust_witness_votes( a, o.amount.amount, 0 ); + db().adjust_proxied_witness_votes( a, o.amount.amount, 0 ); }); db().modify( from_account, [&]( account_object& a ){ - db().adjust_witness_votes( a, -o.amount.amount, 0 ); + db().adjust_proxied_witness_votes( a, -o.amount.amount, 0 ); a.vesting_shares -= o.amount; }); #endif @@ -332,12 +361,12 @@ void withdraw_vesting_evaluator::do_apply( const withdraw_vesting_operation& o ) { const auto& account = db().get_account( o.account ); - if( !db().has_hardfork( STEEMIT_HARDFORK_1 ) ) FC_ASSERT( o.vesting_shares.amount > 0 ); + if( !db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) FC_ASSERT( o.vesting_shares.amount > 0 ); FC_ASSERT( account.vesting_shares >= asset( 0, VESTS_SYMBOL ) ); FC_ASSERT( account.vesting_shares >= o.vesting_shares ); - if( !account.mined && db().has_hardfork( STEEMIT_HARDFORK_1 ) ) { + if( !account.mined && db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) { const auto& props = db().get_dynamic_global_properties(); const witness_schedule_object& wso = db().get_witness_schedule_object(); @@ -375,7 +404,7 @@ void account_witness_proxy_evaluator::do_apply( const account_witness_proxy_oper FC_ASSERT( account.proxy != o.proxy, "something must change" ); /// remove all current votes - db().adjust_witness_votes( account, -account.witness_vote_weight() ); + db().adjust_proxied_witness_votes( account, -account.witness_vote_weight() ); if( o.proxy.size() ) { const auto& new_proxy = db().get_account( o.proxy ); @@ -399,7 +428,7 @@ void account_witness_proxy_evaluator::do_apply( const account_witness_proxy_oper }); /// add all new votes - db().adjust_witness_votes( account, account.witness_vote_weight() ); + db().adjust_proxied_witness_votes( account, account.witness_vote_weight() ); } else { /// we are clearing the proxy which means we simply update the account db().modify( account, [&]( account_object& a ) { a.proxy = o.proxy; @@ -421,7 +450,7 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat if( itr == by_account_witness_idx.end() ) { FC_ASSERT( o.approve, "vote doesn't exist, user must be indicate a desire to approve witness" ); - if ( db().has_hardfork( STEEMIT_HARDFORK_2 ) ) + if ( db().has_hardfork( STEEMIT_HARDFORK_0_2_0 ) ) { FC_ASSERT( voter.witnesses_voted_for < STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, "account has voted for too many witnesses" ); // TODO: Remove after hardfork 2 @@ -430,11 +459,11 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat v.account = voter.id; }); - if( db().has_hardfork( STEEMIT_HARDFORK_3 ) ) { + if( db().has_hardfork( STEEMIT_HARDFORK_0_3_0 ) ) { db().adjust_witness_vote( witness, voter.witness_vote_weight() ); } else { - db().adjust_witness_votes( voter, voter.witness_vote_weight() ); + db().adjust_proxied_witness_votes( voter, voter.witness_vote_weight() ); } } else { @@ -455,11 +484,11 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat } else { FC_ASSERT( !o.approve, "vote currently exists, user must be indicate a desire to reject witness" ); - if ( db().has_hardfork( STEEMIT_HARDFORK_2 ) ) { - if( db().has_hardfork( STEEMIT_HARDFORK_3 ) ) + if ( db().has_hardfork( STEEMIT_HARDFORK_0_2_0 ) ) { + if( db().has_hardfork( STEEMIT_HARDFORK_0_3_0 ) ) db().adjust_witness_vote( witness, -voter.witness_vote_weight() ); else - db().adjust_witness_votes( voter, -voter.witness_vote_weight() ); + db().adjust_proxied_witness_votes( voter, -voter.witness_vote_weight() ); } else { db().modify( witness, [&]( witness_object& w ) { w.votes -= voter.witness_vote_weight(); @@ -472,7 +501,7 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat } } -void vote_evaluator::do_apply( const vote_operation& o ) +void vote_evaluator::do_apply( const vote_operation& o ) { try { const auto& comment = db().get_comment( o.author, o.permlink ); @@ -528,14 +557,14 @@ void vote_evaluator::do_apply( const vote_operation& o ) }); /** this verifies uniqueness of voter - * + * * voter_weight / new_total_weight ==> % of total vote weight provided by voter * percent^2 => used to create non-linear reward toward those who contribute a larger percentage * * voter_weight * percent^2 ==> used to keep rewards proportional to vote_weight (small voters shouldn't get larger rewards simply for being first) * * Simplify equation as: - * vote_weight * (voter_weight/new_total_weight)^2 + * vote_weight * (voter_weight/new_total_weight)^2 * vote_weight * (voter_weight^2 / new_total_weight^2) * vote_weight^3 / new_total_weight^2 * @@ -703,7 +732,7 @@ void limit_order_cancel_evaluator::do_apply( const limit_order_cancel_operation& void report_over_production_evaluator::do_apply( const report_over_production_operation& o ) { FC_ASSERT( !db().is_producing(), "this operation is currently disabled" ); - FC_ASSERT( !db().has_hardfork( STEEMIT_HARDFORK_4 ), "this operation is disabled after this hardfork" ); + FC_ASSERT( !db().has_hardfork( STEEMIT_HARDFORK_0_4_0 ), "this operation is disabled after this hardfork" ); /* const auto& reporter = db().get_account( o.reporter ); @@ -716,10 +745,10 @@ void report_over_production_evaluator::do_apply( const report_over_production_op db().modify( reporter, [&]( account_object& a ){ a.vesting_shares += violator.vesting_shares; - db().adjust_witness_votes( a, violator.vesting_shares.amount, 0 ); + db().adjust_proxied_witness_votes( a, violator.vesting_shares.amount, 0 ); }); db().modify( violator, [&]( account_object& a ){ - db().adjust_witness_votes( a, -a.vesting_shares.amount, 0 ); + db().adjust_proxied_witness_votes( a, -a.vesting_shares.amount, 0 ); a.vesting_shares.amount = 0; }); */ diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 2058c95c20..1dd5f27fe8 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -52,8 +52,17 @@ clean_database_fixture::clean_database_fixture() ahplugin->plugin_initialize( options ); generate_block(); + db.set_hardfork( STEEMIT_NUM_HARDFORKS ); vest( "initminer", 10000 ); + // Fill up the rest of the required miners + for( int i = STEEMIT_NUM_INIT_MINERS; i < STEEMIT_MAX_MINERS; i++ ) + { + account_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_pub_key ); + fund( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), STEEMIT_MIN_PRODUCER_REWARD.amount.value ); + witness_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_priv_key, "foo.bar", init_account_pub_key, STEEMIT_MIN_PRODUCER_REWARD.amount ); + } + validate_database(); } catch ( const fc::exception& e ) { @@ -363,21 +372,11 @@ void database_fixture::set_price_feed( const price& new_price ) { for ( int i = 1; i < 8; i++ ) { - try - { - db.get_witness( "STEEMIT_INIT_MINER_NAME + fc::to_string( i )" ); - } - catch ( fc::assert_exception e ) - { - account_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_pub_key ); - fund( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), STEEMIT_MIN_PRODUCER_REWARD.amount.value ); - witness_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_priv_key, "foo.bar", init_account_pub_key, STEEMIT_MIN_PRODUCER_REWARD.amount ); - } - feed_publish_operation op; op.publisher = STEEMIT_INIT_MINER_NAME + fc::to_string( i ); op.exchange_rate = new_price; trx.operations.push_back( op ); + trx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); db.push_transaction( trx, ~0 ); trx.operations.clear(); } @@ -457,6 +456,7 @@ void database_fixture::validate_database( void ) } fc::uint128_t total_rshares2; + fc::uint128_t total_children_rshares2; const auto& comment_idx = db.get_index_type< comment_index >().indices().get< by_id >(); @@ -464,6 +464,8 @@ void database_fixture::validate_database( void ) { if( itr->net_rshares.value > 0 ) total_rshares2 += fc::uint128_t( itr->net_rshares.value ) * itr->net_rshares.value; + if( itr->parent_author.size() == 0 ) + total_children_rshares2 += itr->children_rshares2; } auto gpo = db.get_dynamic_global_properties(); @@ -471,12 +473,12 @@ void database_fixture::validate_database( void ) total_supply += gpo.total_vesting_fund_steem + gpo.total_reward_fund_steem; - BOOST_REQUIRE_EQUAL( gpo.current_supply.amount.value, total_supply.amount.value ); - BOOST_REQUIRE_EQUAL( gpo.current_sbd_supply.amount.value, total_sbd.amount.value ); - BOOST_REQUIRE_EQUAL( gpo.total_vesting_shares.amount.value, total_vesting.amount.value ); - BOOST_REQUIRE_EQUAL( gpo.total_vesting_shares.amount.value, total_vsf_votes.value ); - BOOST_REQUIRE( gpo.total_reward_shares2 == total_rshares2 ); - BOOST_REQUIRE( gpo.virtual_supply >= gpo.current_supply ); + FC_ASSERT( gpo.current_supply == total_supply, "", ("gpo.current_supply",gpo.current_supply)("total_supply",total_supply) ); + FC_ASSERT( gpo.current_sbd_supply == total_sbd, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("total_sbd",total_sbd) ); + FC_ASSERT( gpo.total_vesting_shares == total_vesting, "", ("gpo.total_vesting_shares",gpo.total_vesting_shares)("total_vesting",total_vesting) ); + FC_ASSERT( gpo.total_vesting_shares.amount == total_vsf_votes, "", ("total_vesting_shares",gpo.total_vesting_shares)("total_vsf_votes",total_vsf_votes) ); + FC_ASSERT( gpo.total_reward_shares2 == total_rshares2, "", ("gpo.total",gpo.total_reward_shares2)("check.total",total_rshares2)("delta",gpo.total_reward_shares2-total_rshares2)); + FC_ASSERT( total_rshares2 == total_children_rshares2, "", ("total_rshares2", total_rshares2)("total_children_rshares2",total_children_rshares2)); if ( !db.get_feed_history().current_median_history.is_null() ) BOOST_REQUIRE( gpo.current_sbd_supply * db.get_feed_history().current_median_history + gpo.current_supply == gpo.virtual_supply ); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 2aee38e09d..a4667337c5 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -976,15 +977,56 @@ BOOST_FIXTURE_TEST_CASE( hardfork_test, database_fixture ) { try { + /* Setup code from clean fixture sans setting hardforks */ + try { + int argc = boost::unit_test::framework::master_test_suite().argc; + char** argv = boost::unit_test::framework::master_test_suite().argv; + for( int i=1; i(); + init_account_pub_key = init_account_priv_key.get_public_key(); + + boost::program_options::variables_map options; + + open_database(); + + // app.initialize(); + ahplugin->plugin_set_app( &app ); + ahplugin->plugin_initialize( options ); + + generate_block(); + vest( "initminer", 10000 ); + + // Fill up the rest of the required miners + for( int i = STEEMIT_NUM_INIT_MINERS; i < STEEMIT_MAX_MINERS; i++ ) + { + account_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_pub_key ); + fund( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), STEEMIT_MIN_PRODUCER_REWARD.amount.value ); + witness_create( STEEMIT_INIT_MINER_NAME + fc::to_string( i ), init_account_priv_key, "foo.bar", init_account_pub_key, STEEMIT_MIN_PRODUCER_REWARD.amount ); + } + + validate_database(); + } catch ( const fc::exception& e ) + { + edump( (e.to_detail_string()) ); + throw; + } + BOOST_TEST_MESSAGE( "Check hardfork not applied at genesis" ); BOOST_REQUIRE( db.has_hardfork( 0 ) ); - BOOST_REQUIRE( !db.has_hardfork( STEEMIT_HARDFORK_1 ) ); + BOOST_REQUIRE( !db.has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ); BOOST_TEST_MESSAGE( "Generate blocks up to the hardfork time and check hardfork still not applied" ); - generate_blocks( fc::time_point_sec( STEEMIT_HARDFORK_1_TIME - STEEMIT_BLOCK_INTERVAL ), true ); + generate_blocks( fc::time_point_sec( STEEMIT_HARDFORK_0_1_0_TIME - STEEMIT_BLOCK_INTERVAL ), true ); BOOST_REQUIRE( db.has_hardfork( 0 ) ); - BOOST_REQUIRE( !db.has_hardfork( STEEMIT_HARDFORK_1 ) ); + BOOST_REQUIRE( !db.has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ); BOOST_TEST_MESSAGE( "Generate a block and check hardfork is applied" ); generate_block(); @@ -994,7 +1036,7 @@ BOOST_FIXTURE_TEST_CASE( hardfork_test, database_fixture ) itr--; BOOST_REQUIRE( db.has_hardfork( 0 ) ); - BOOST_REQUIRE( db.has_hardfork( STEEMIT_HARDFORK_1 ) ); + BOOST_REQUIRE( db.has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ); BOOST_REQUIRE( get_last_operations( 1 )[0].get< custom_operation >().data == vector< char >( op_msg.begin(), op_msg.end() ) ); BOOST_REQUIRE( itr->op(db).timestamp == db.head_block_time() ); @@ -1005,7 +1047,7 @@ BOOST_FIXTURE_TEST_CASE( hardfork_test, database_fixture ) itr--; BOOST_REQUIRE( db.has_hardfork( 0 ) ); - BOOST_REQUIRE( db.has_hardfork( STEEMIT_HARDFORK_1 ) ); + BOOST_REQUIRE( db.has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ); BOOST_REQUIRE( get_last_operations( 1 )[0].get< custom_operation >().data == vector< char >( op_msg.begin(), op_msg.end() ) ); BOOST_REQUIRE( itr->op(db).timestamp == db.head_block_time() - STEEMIT_BLOCK_INTERVAL ); } diff --git a/tests/tests/live_tests.cpp b/tests/tests/live_tests.cpp index 362599ddd6..256a4f4a9c 100644 --- a/tests/tests/live_tests.cpp +++ b/tests/tests/live_tests.cpp @@ -167,6 +167,34 @@ BOOST_AUTO_TEST_CASE( vests_stock_split ) FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( retally_votes ) +{ + try + { + flat_map< witness_id_type, share_type > expected_votes; + + const auto& by_account_witness_idx = db.get_index_type< witness_vote_index >().indices(); + + for( auto vote: by_account_witness_idx ) + { + if( expected_votes.find( vote.witness ) == expected_votes.end() ) + expected_votes[ vote.witness ] = vote.account( db ).witness_vote_weight(); + else + expected_votes[ vote.witness ] += vote.account( db ).witness_vote_weight(); + } + + db.retally_witness_votes(); + + const auto& witness_idx = db.get_index_type< witness_index >().indices(); + + for( auto witness: witness_idx ) + { + BOOST_REQUIRE_EQUAL( witness.votes.value, expected_votes[ witness.id ].value ); + } + } + FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_SUITE_END() #endif \ No newline at end of file diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index eb9f79b4a7..894a82ea86 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -491,13 +491,26 @@ BOOST_AUTO_TEST_CASE( comment_apply ) generate_blocks( 60 / STEEMIT_BLOCK_INTERVAL + 1 ); BOOST_TEST_MESSAGE( "--- Test modifying a comment" ); - const comment_object& mod_sam_comment = db.get_comment( "sam", "dolor" ); + const auto& mod_sam_comment = db.get_comment( "sam", "dolor" ); + const auto& mod_bob_comment = db.get_comment( "bob", "ipsum" ); + const auto& mod_alice_comment = db.get_comment( "alice", "lorem" ); fc::time_point_sec created = mod_sam_comment.created; db.modify( mod_sam_comment, [&]( comment_object& com ) { com.net_rshares = 10; com.abs_rshares = 10; + com.children_rshares2 = 100; + }); + + db.modify( mod_bob_comment, [&]( comment_object& com) + { + com.children_rshares2 = 100; + }); + + db.modify( mod_alice_comment, [&]( comment_object& com) + { + com.children_rshares2 = 100; }); db.modify( db.get_dynamic_global_properties(), [&]( dynamic_global_property_object& o) @@ -527,7 +540,6 @@ BOOST_AUTO_TEST_CASE( comment_apply ) validate_database(); BOOST_TEST_MESSAGE( "--- Test failure posting withing 1 minute" ); - generate_blocks( 60 / STEEMIT_BLOCK_INTERVAL ); op.permlink = "sit"; tx.operations.clear(); @@ -535,6 +547,16 @@ BOOST_AUTO_TEST_CASE( comment_apply ) tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); tx.operations.push_back( op ); tx.sign( sam_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + generate_blocks( 60 / STEEMIT_BLOCK_INTERVAL ); + + op.permlink = "amet"; + tx.operations.clear(); + tx.signatures.clear(); + tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); + tx.operations.push_back( op ); + tx.sign( sam_private_key, db.get_chain_id() ); STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); validate_database(); @@ -701,9 +723,9 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_TEST_MESSAGE( "--- Test payout time extension on vote" ); - fc::time_point_sec old_cashout_time = alice_comment.cashout_time; + uint128_t old_cashout_time = alice_comment.cashout_time.sec_since_epoch(); old_voting_power = bob.voting_power; - auto old_net_rshares = alice_comment.net_rshares.value; + auto old_abs_rshares = alice_comment.abs_rshares.value; generate_blocks( db.head_block_time() + fc::seconds( ( STEEMIT_CASHOUT_WINDOW_SECONDS / 2 ) ), true ); @@ -723,10 +745,13 @@ BOOST_AUTO_TEST_CASE( vote_apply ) db.push_transaction( tx, 0 ); itr = vote_idx.find( std::make_tuple( new_alice_comment.id, new_bob.id ) ); + uint128_t new_cashout_time = db.head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS; BOOST_REQUIRE_EQUAL( new_bob.voting_power, STEEMIT_100_PERCENT - ( STEEMIT_100_PERCENT / 20 ) ); - BOOST_REQUIRE_EQUAL( new_alice_comment.net_rshares.value, old_net_rshares + new_bob.vesting_shares.amount.value * ( old_voting_power - new_bob.voting_power ) / STEEMIT_100_PERCENT ); - BOOST_REQUIRE_EQUAL( new_alice_comment.cashout_time.sec_since_epoch(), fc::time_point_sec( uint32_t( ( ( ( uint64_t( old_cashout_time.sec_since_epoch() ) * old_net_rshares ) + ( ( db.head_block_time() + fc::seconds( STEEMIT_CASHOUT_WINDOW_SECONDS ) ).sec_since_epoch() * bob_weight ) ) / new_alice_comment.abs_rshares ).value ) ).sec_since_epoch() ); + BOOST_REQUIRE_EQUAL( new_alice_comment.net_rshares.value, old_abs_rshares + new_bob.vesting_shares.amount.value * ( old_voting_power - new_bob.voting_power ) / STEEMIT_100_PERCENT ); + BOOST_REQUIRE_EQUAL( new_alice_comment.cashout_time.sec_since_epoch(), + ( ( old_cashout_time * old_abs_rshares + new_cashout_time * bob_weight ) + / ( old_abs_rshares + bob_weight ) ).to_uint64() ); BOOST_REQUIRE( itr != vote_idx.end() ); validate_database(); @@ -735,8 +760,8 @@ BOOST_AUTO_TEST_CASE( vote_apply ) const auto& new_sam = db.get_account( "sam" ); const auto& new_bob_comment = db.get_comment( "bob", "foo" ); - old_cashout_time = new_bob_comment.cashout_time; - old_net_rshares = new_bob_comment.net_rshares.value; + old_cashout_time = new_bob_comment.cashout_time.sec_since_epoch(); + old_abs_rshares = new_bob_comment.abs_rshares.value; auto sam_weight = ( ( uint128_t( new_sam.vesting_shares.amount.value ) ) / 40 ).to_uint64(); @@ -751,11 +776,14 @@ BOOST_AUTO_TEST_CASE( vote_apply ) db.push_transaction( tx, 0 ); itr = vote_idx.find( std::make_tuple( new_bob_comment.id, new_sam.id ) ); + new_cashout_time = db.head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS; BOOST_REQUIRE_EQUAL( new_sam.voting_power, STEEMIT_100_PERCENT - ( STEEMIT_100_PERCENT / 40 ) ); - BOOST_REQUIRE_EQUAL( new_bob_comment.net_rshares.value, old_net_rshares - sam_weight ); - BOOST_REQUIRE_EQUAL( new_bob_comment.abs_rshares.value, old_net_rshares + sam_weight ); - BOOST_REQUIRE( new_bob_comment.cashout_time == fc::time_point_sec( uint32_t( ( ( ( uint64_t( old_cashout_time.sec_since_epoch() ) * old_net_rshares ) + ( ( db.head_block_time() + fc::seconds( STEEMIT_CASHOUT_WINDOW_SECONDS ) ).sec_since_epoch() * sam_weight ) ) / new_bob_comment.abs_rshares ).value ) ) ); + BOOST_REQUIRE_EQUAL( new_bob_comment.net_rshares.value, old_abs_rshares - sam_weight ); + BOOST_REQUIRE_EQUAL( new_bob_comment.abs_rshares.value, old_abs_rshares + sam_weight ); + BOOST_REQUIRE_EQUAL( new_bob_comment.cashout_time.sec_since_epoch(), + ( ( old_cashout_time * old_abs_rshares + new_cashout_time * sam_weight ) + / ( old_abs_rshares + sam_weight ) ).to_uint64() ); BOOST_REQUIRE( itr != vote_idx.end() ); validate_database(); @@ -1117,6 +1145,8 @@ BOOST_AUTO_TEST_CASE( withdraw_vesting_apply ) fund( "alice", 10000 ); vest( "alice", 10000 ); + BOOST_TEST_MESSAGE( "--- Test withdraw of existing VESTS" ); + withdraw_vesting_operation op; op.account = "alice"; op.vesting_shares = asset( alice.vesting_shares.amount / 2, VESTS_SYMBOL ); @@ -1131,8 +1161,11 @@ BOOST_AUTO_TEST_CASE( withdraw_vesting_apply ) BOOST_REQUIRE_EQUAL( alice.vesting_shares.amount.value, old_vesting_shares.amount.value ); BOOST_REQUIRE_EQUAL( alice.vesting_withdraw_rate.amount.value, ( old_vesting_shares.amount / 208 ).value ); + BOOST_REQUIRE_EQUAL( alice.to_withdraw.value, op.vesting_shares.amount.value ); + BOOST_REQUIRE( alice.next_vesting_withdrawal == db.head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS ); validate_database(); + BOOST_TEST_MESSAGE( "--- Test changing vesting withdrawal" ); tx.operations.clear(); tx.signatures.clear(); @@ -1144,12 +1177,16 @@ BOOST_AUTO_TEST_CASE( withdraw_vesting_apply ) BOOST_REQUIRE_EQUAL( alice.vesting_shares.amount.value, old_vesting_shares.amount.value ); BOOST_REQUIRE_EQUAL( alice.vesting_withdraw_rate.amount.value, ( old_vesting_shares.amount / 312 ).value ); + BOOST_REQUIRE_EQUAL( alice.to_withdraw.value, op.vesting_shares.amount.value ); + BOOST_REQUIRE( alice.next_vesting_withdrawal == db.head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS ); validate_database(); + BOOST_TEST_MESSAGE( "--- Test withdrawing more vests than available" ); + auto old_withdraw_amount = alice.to_withdraw; tx.operations.clear(); tx.signatures.clear(); - op.vesting_shares = ASSET( "15.000000 VESTS" ); + op.vesting_shares = asset( alice.vesting_shares.amount * 2, VESTS_SYMBOL ); tx.operations.push_back( op ); tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); tx.sign( alice_private_key, db.get_chain_id() ); @@ -1157,7 +1194,23 @@ BOOST_AUTO_TEST_CASE( withdraw_vesting_apply ) BOOST_REQUIRE_EQUAL( alice.vesting_shares.amount.value, old_vesting_shares.amount.value ); BOOST_REQUIRE_EQUAL( alice.vesting_withdraw_rate.amount.value, ( old_vesting_shares.amount / 312 ).value ); + BOOST_REQUIRE( alice.next_vesting_withdrawal == db.head_block_time() + STEEMIT_VESTING_WITHDRAW_INTERVAL_SECONDS ); validate_database(); + + BOOST_TEST_MESSAGE( "--- Test withdrawing 0 to resent vesting withdraw" ); + tx.operations.clear(); + tx.signatures.clear(); + + op.vesting_shares = asset( 0, VESTS_SYMBOL ); + tx.operations.push_back( op ); + tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); + tx.sign( alice_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + BOOST_REQUIRE_EQUAL( alice.vesting_shares.amount.value, old_vesting_shares.amount.value ); + BOOST_REQUIRE_EQUAL( alice.vesting_withdraw_rate.amount.value, 0 ); + BOOST_REQUIRE_EQUAL( alice.to_withdraw.value, 0 ); + BOOST_REQUIRE( alice.next_vesting_withdrawal == fc::time_point_sec::maximum() ); } FC_LOG_AND_RETHROW() } @@ -1269,8 +1322,8 @@ BOOST_AUTO_TEST_CASE( witness_update_apply ) BOOST_REQUIRE_EQUAL( alice_witness.votes.value, 0 ); BOOST_REQUIRE( alice_witness.virtual_last_update == 0 ); BOOST_REQUIRE( alice_witness.virtual_position == 0 ); - BOOST_REQUIRE( alice_witness.virtual_scheduled_time == 0 ); - BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "9.000 TESTS" ).amount.value ); + BOOST_REQUIRE( alice_witness.virtual_scheduled_time == fc::uint128_t::max_value() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "10.000 TESTS" ).amount.value ); // No fee validate_database(); BOOST_TEST_MESSAGE( "--- Test updating a witness" ); @@ -1296,8 +1349,8 @@ BOOST_AUTO_TEST_CASE( witness_update_apply ) BOOST_REQUIRE_EQUAL( alice_witness.votes.value, 0 ); BOOST_REQUIRE( alice_witness.virtual_last_update == 0 ); BOOST_REQUIRE( alice_witness.virtual_position == 0 ); - BOOST_REQUIRE( alice_witness.virtual_scheduled_time == 0 ); - BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "9.000 TESTS" ).amount.value ); + BOOST_REQUIRE( alice_witness.virtual_scheduled_time == fc::uint128_t::max_value() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "10.000 TESTS" ).amount.value ); validate_database(); BOOST_TEST_MESSAGE( "--- Test failure when upgrading a non-existent account" ); @@ -1309,18 +1362,6 @@ BOOST_AUTO_TEST_CASE( witness_update_apply ) tx.sign( alice_private_key, db.get_chain_id() ); STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); validate_database(); - - BOOST_TEST_MESSAGE( "--- Test failure when account cannot cover upgrade fee" ); - - ACTORS( (bob) ); - fund( "bob", 500 ); - op.fee = ASSET( "1.000 TESTS" ); - tx.signatures.clear(); - tx.operations.clear(); - tx.operations.push_back( op ); - tx.sign( bob_private_key, db.get_chain_id() ); - STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); - validate_database(); } FC_LOG_AND_RETHROW() } diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index 60c22dc027..8ea494b078 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -12,7 +12,6 @@ #include "../common/database_fixture.hpp" #include -#include using namespace steemit::chain; using namespace steemit::chain::test; @@ -174,7 +173,7 @@ BOOST_AUTO_TEST_CASE( comment_payout ) auto bob_comment_reward = get_last_operations( 1 )[0].get< comment_reward_operation >(); - BOOST_REQUIRE_EQUAL( ( db.get_dynamic_global_properties().total_reward_fund_steem + bob_comment_payout + bob_comment_vote_rewards - unclaimed_payments ).amount.value, reward_steem.amount.value ); + BOOST_REQUIRE_EQUAL( db.get_dynamic_global_properties().total_reward_fund_steem.amount.value, reward_steem.amount.value - ( bob_comment_payout + bob_comment_vote_rewards - unclaimed_payments ).amount.value ); BOOST_REQUIRE_EQUAL( db.get_comment( "bob", "test" ).total_payout_value.amount.value, ( ( bob_comment_vesting_reward * db.get_dynamic_global_properties().get_vesting_share_price() ) + ( bob_comment_sbd_reward * exchange_rate ) ).amount.value ); BOOST_REQUIRE_EQUAL( db.get_account( "bob" ).sbd_balance.amount.value, ( bob_sbd_balance + bob_comment_sbd_reward ).amount.value ); BOOST_REQUIRE( db.get_comment( "alice", "test" ).net_rshares.value > 0 ); @@ -223,7 +222,13 @@ BOOST_AUTO_TEST_CASE( comment_payout ) sam_vest_shares = db.get_account( "sam" ).vesting_shares; dave_vest_shares = db.get_account( "dave" ).vesting_shares; - auto alice_comment_payout = asset( ( ( uint128_t( alice_comment_rshares.value ) * alice_comment_rshares.value * reward_steem.amount.value ) / total_rshares2 ).to_uint64(), STEEM_SYMBOL ); + u256 rs( alice_comment_rshares.value ); + u256 rf( reward_steem.amount.value ); + u256 trs2 = total_rshares2.hi; + trs2 = ( trs2 << 64 ) + total_rshares2.lo; + auto rs2 = rs*rs; + + auto alice_comment_payout = asset( static_cast< uint64_t >( ( rf * rs2 ) / trs2 ), STEEM_SYMBOL ); auto alice_comment_vote_rewards = asset( alice_comment_payout.amount / 2, STEEM_SYMBOL ); alice_comment_payout -= alice_comment_vote_rewards; auto alice_comment_sbd_reward = asset( alice_comment_payout.amount / 2, STEEM_SYMBOL ) * exchange_rate; @@ -240,7 +245,6 @@ BOOST_AUTO_TEST_CASE( comment_payout ) unclaimed_payments -= ( alice_vote_reward + bob_vote_reward + sam_vote_reward + dave_vote_reward ); generate_block(); - auto alice_comment_reward = get_last_operations( 1 )[0].get< comment_reward_operation >(); BOOST_REQUIRE_EQUAL( ( db.get_dynamic_global_properties().total_reward_fund_steem + alice_comment_payout + alice_comment_vote_rewards - unclaimed_payments ).amount.value, reward_steem.amount.value ); @@ -654,8 +658,6 @@ BOOST_AUTO_TEST_CASE( vesting_withdrawals ) fund( "alice", 100000 ); vest( "alice", 100000 ); - generate_blocks( fc::time_point_sec( STEEMIT_HARDFORK_1_TIME ), true ); // Get past the test hardfork time - const auto& new_alice = db.get_account( "alice" ); BOOST_TEST_MESSAGE( "Setting up withdrawal" ); @@ -1235,8 +1237,6 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) { ACTORS( (alice)(bob)(sam)(dave) ) - generate_blocks( fc::time_point_sec( STEEMIT_HARDFORK_1_TIME ), true ); - BOOST_TEST_MESSAGE( "Rewarding Bob with TESTS" ); auto exchange_rate = price( ASSET( "1.250 TESTS" ), ASSET( "1.000 TBD" ) );