From 1e1bd9ed2eec5c6020af7abb80b9bd48d85390a3 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 26 Apr 2016 10:59:22 -0400 Subject: [PATCH 01/20] Initial implementation --- libraries/chain/database.cpp | 13 +- .../include/steemit/chain/comment_object.hpp | 3 +- libraries/chain/steem_evaluator.cpp | 145 ++++++++++-------- 3 files changed, 94 insertions(+), 67 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 20cd1dad87..6027a5425d 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1212,11 +1212,14 @@ 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 ) { - 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( itr->weight > 0 ) + { + 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 ) ); + } ++itr; } if( max_rewards.value - unclaimed_rewards.value ) diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index 2af5c87405..d50ef594fb 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -116,6 +116,7 @@ namespace steemit { namespace chain { account_id_type voter; comment_id_type comment; uint64_t weight = 0; ///< defines the score this vote receives, used by vote payout calc. 0 if a negative vote. + int64_t rshares = 0; ///< The number of rshares this vote is responsible for }; struct by_comment_voter; @@ -337,6 +338,6 @@ FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), (net_rshares)(abs_rshares)(cashout_time)(total_vote_weight)(total_payout_value) ) FC_REFLECT_DERIVED( steemit::chain::comment_vote_object, (graphene::db::object), - (voter)(comment)(weight) ) + (voter)(comment)(weight)(rshares) ) FC_REFLECT_DERIVED( steemit::chain::category_object, (graphene::db::object), (name)(abs_rshares)(total_payouts)(discussions)(last_update) ); diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 1af7c66ec8..d0bfaf895c 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -475,7 +475,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_2 ) ) { FC_ASSERT( voter.witnesses_voted_for < STEEMIT_MAX_ACCOUNT_WITNESS_VOTES, "account has voted for too many witnesses" ); // TODO: Remove after hardfork 2 @@ -521,84 +521,107 @@ void account_witness_vote_evaluator::do_apply( const account_witness_vote_operat void vote_evaluator::do_apply( const vote_operation& o ) { const auto& comment = db().get_comment( o.author, o.permlink ); const auto& voter = db().get_account( o.voter ); + const auto& comment_vote_idx = db().get_index_type< comment_vote_index >().indices().get< by_comment_voter >(); + auto itr = comment_vote_idx.find( std::make_tuple( comment.id, voter.id ) ); - auto elapsed_seconds = (db().head_block_time() - voter.last_vote_time).to_seconds(); - auto regenerated_power = ((STEEMIT_100_PERCENT - voter.voting_power) * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; - auto current_power = std::min( int64_t(voter.voting_power + regenerated_power), int64_t(STEEMIT_100_PERCENT) ); - FC_ASSERT( current_power > 0 ); + if( itr == comment_vote_idx.end() ) + { + auto elapsed_seconds = (db().head_block_time() - voter.last_vote_time).to_seconds(); + auto regenerated_power = ((STEEMIT_100_PERCENT - voter.voting_power) * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; + auto current_power = std::min( int64_t(voter.voting_power + regenerated_power), int64_t(STEEMIT_100_PERCENT) ); + FC_ASSERT( current_power > 0 ); - int64_t abs_weight = abs(o.weight); - auto used_power = (current_power * abs_weight) / STEEMIT_100_PERCENT; - used_power /= 20; /// a 100% vote means use 5% of voting power which should force users to spread their votes around over 20+ posts + int64_t abs_weight = abs(o.weight); + auto used_power = (current_power * abs_weight) / STEEMIT_100_PERCENT; + used_power /= 20; /// a 100% vote means use 5% of voting power which should force users to spread their votes around over 20+ posts - int64_t abs_rshares = ((uint128_t(voter.vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); + int64_t abs_rshares = ((uint128_t(voter.vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); - /// this is the rshares voting for or against the post - int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; + /// this is the rshares voting for or against the post + int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; - db().modify( voter, [&]( account_object& a ){ - a.voting_power = current_power - used_power; - a.last_vote_time = db().head_block_time(); - }); + db().modify( voter, [&]( account_object& a ){ + a.voting_power = current_power - used_power; + a.last_vote_time = db().head_block_time(); + }); - /// if the current net_rshares is less than 0, the post is getting 0 rewards so it is not factored into total rshares^2 - fc::uint128_t old_rshares = std::max(comment.net_rshares.value, int64_t(0)); - auto old_abs_rshares = comment.abs_rshares.value; + /// if the current net_rshares is less than 0, the post is getting 0 rewards so it is not factored into total rshares^2 + fc::uint128_t old_rshares = std::max(comment.net_rshares.value, int64_t(0)); + auto old_abs_rshares = comment.abs_rshares.value; - fc::uint128_t cur_cashout_time_sec = comment.cashout_time.sec_since_epoch(); - fc::uint128_t new_cashout_time_sec = db().head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS; - auto avg_cashout_sec = (cur_cashout_time_sec * old_abs_rshares + new_cashout_time_sec * abs_rshares ) / (comment.abs_rshares.value + abs_rshares ); + fc::uint128_t cur_cashout_time_sec = comment.cashout_time.sec_since_epoch(); + fc::uint128_t new_cashout_time_sec = db().head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS; + auto avg_cashout_sec = (cur_cashout_time_sec * old_abs_rshares + new_cashout_time_sec * abs_rshares ) / (comment.abs_rshares.value + abs_rshares ); - FC_ASSERT( abs_rshares > 0 ); + FC_ASSERT( abs_rshares > 0 ); -// idump( (db().get_dynamic_global_properties().total_reward_shares2 )(comment.net_rshares)(abs_rshares)(o.weight)(rshares) ); + // idump( (db().get_dynamic_global_properties().total_reward_shares2 )(comment.net_rshares)(abs_rshares)(o.weight)(rshares) ); - db().modify( comment, [&]( comment_object& c ){ - c.net_rshares += rshares; - c.abs_rshares += abs_rshares; - c.cashout_time = fc::time_point_sec( ) + fc::seconds(avg_cashout_sec.to_uint64()); - }); + db().modify( comment, [&]( comment_object& c ){ + c.net_rshares += rshares; + c.abs_rshares += abs_rshares; + c.cashout_time = fc::time_point_sec( ) + fc::seconds(avg_cashout_sec.to_uint64()); + }); - fc::uint128_t new_rshares = std::max( comment.net_rshares.value, int64_t(0)); + fc::uint128_t new_rshares = std::max( comment.net_rshares.value, int64_t(0)); - /// square it - new_rshares *= new_rshares; - old_rshares *= old_rshares; + /// square it + new_rshares *= new_rshares; + old_rshares *= old_rshares; - const auto& cprops = db().get_dynamic_global_properties(); - auto orig_total = cprops.total_reward_shares2; - db().modify( cprops, [&]( dynamic_global_property_object& p ){ - // idump( (old_rshares)(new_rshares)(comment.author)(comment.permlink) ); - p.total_reward_shares2 += new_rshares; - p.total_reward_shares2 -= old_rshares; - // idump((p.total_reward_shares2 - orig_total)); - }); - // idump((new_rshares - old_rshares)); - // idump( (db().get_dynamic_global_properties().total_reward_shares2)(comment.net_rshares) ); + const auto& cprops = db().get_dynamic_global_properties(); + auto orig_total = cprops.total_reward_shares2; + db().modify( cprops, [&]( dynamic_global_property_object& p ){ + // idump( (old_rshares)(new_rshares)(comment.author)(comment.permlink) ); + p.total_reward_shares2 += new_rshares; + p.total_reward_shares2 -= old_rshares; + // idump((p.total_reward_shares2 - orig_total)); + }); + // idump((new_rshares - old_rshares)); + // idump( (db().get_dynamic_global_properties().total_reward_shares2)(comment.net_rshares) ); - const auto& cat = db().get_category( comment.category ); - db().modify( cat, [&]( category_object& c ){ - c.abs_rshares += abs_rshares; - c.last_update = db().head_block_time(); - }); + const auto& cat = db().get_category( comment.category ); + db().modify( cat, [&]( category_object& c ){ + c.abs_rshares += abs_rshares; + c.last_update = db().head_block_time(); + }); - /** this verifies uniqueness of voter */ - const auto& cvo = db().create( [&]( comment_vote_object& cv ){ - cv.voter = voter.id; - cv.comment = comment.id; - if( rshares > 0 ) { - u256 rshare256(rshares); - u256 total256( comment.abs_rshares.value ); - cv.weight = static_cast( ( ( rshare256 * rshare256 ) / total256 ) * rshare256 ); - } - }); + /** this verifies uniqueness of voter */ + const auto& cvo = db().create( [&]( comment_vote_object& cv ){ + cv.voter = voter.id; + cv.comment = comment.id; + cv.rshares = rshares; + if( rshares > 0 ) { + u256 rshare256(rshares); + u256 total256( comment.abs_rshares.value ); + cv.weight = static_cast( ( ( rshare256 * rshare256 ) / total256 ) * rshare256 ); + } + }); - db().modify( comment, [&]( comment_object& c ){ - c.total_vote_weight += cvo.weight; - }); + db().modify( comment, [&]( comment_object& c ){ + c.total_vote_weight += cvo.weight; + }); + + db().adjust_rshares2( comment, old_rshares, new_rshares ); + } + else + { + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_3 ), "Cannot undo votes until hardfork 3" ); - db().adjust_rshares2( comment, old_rshares, new_rshares ); + db().modify( comment, [&]( comment_object& c ) + { + c.total_vote_weight -= itr->weight; + c.net_rshares -= itr->rshares; + c.abs_rshares -= ( itr->rshares > 0 ? itr->rshares : -itr->rshares ); + }); + + db().modify( *itr, [&]( comment_vote_object& cv ) + { + cv.rshares = 0; + cv.weight = 0; + }); + } } void custom_evaluator::do_apply( const custom_operation& o ){ From 687bc2478b523abb3f8deb0f01e5165e65a13e40 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 26 Apr 2016 13:44:14 -0400 Subject: [PATCH 02/20] Add test cases for expanded op. #22 --- libraries/chain/database.cpp | 19 ++---- libraries/chain/protocol/steem_operations.cpp | 2 +- libraries/chain/steem_evaluator.cpp | 2 + tests/tests/operation_tests.cpp | 65 +++++++++++++++++++ 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 6027a5425d..41746bf9b2 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2375,8 +2375,8 @@ void database::process_hardforks() switch( hardforks.last_hardfork + 1 ) { case STEEMIT_HARDFORK_1: - perform_vesting_share_split( 1000000 ); - break; + perform_vesting_share_split( 1000000 ); + break; #ifdef IS_TEST_NET { custom_operation test_op; @@ -2386,18 +2386,12 @@ void database::process_hardforks() push_applied_operation( test_op ); } break; - #else - // Just in case someone changes the temp account auth between now and the hardfork - // *in best Captain Kirk voice* TROLLLLLLSSS!!!! *shakes fist* - modify( get_account( STEEMIT_TEMP_ACCOUNT ), [&]( account_object& a ) - { - a.owner.weight_threshold = 0; - a.active.weight_threshold = 0; - }); #endif case STEEMIT_HARDFORK_2: retally_witness_votes(); break; + case STEEMIT_HARDFORK_3: + break; default: break; } @@ -2423,9 +2417,10 @@ void database::set_hardfork( uint32_t hardfork ) auto const& hardforks = hardfork_property_id_type()( *this ); - while( hardforks.last_hardfork < hardfork ) + while( hardforks.last_hardfork < hardfork + && hardforks.last_hardfork < STEEMIT_NUM_HARDFORKS ) { - _hardfork_times[ hardforks.last_hardfork ] = head_block_time(); + _hardfork_times[ hardforks.last_hardfork + 1 ] = head_block_time(); process_hardforks(); } } diff --git a/libraries/chain/protocol/steem_operations.cpp b/libraries/chain/protocol/steem_operations.cpp index 9fa588e23f..1171f8c661 100644 --- a/libraries/chain/protocol/steem_operations.cpp +++ b/libraries/chain/protocol/steem_operations.cpp @@ -61,7 +61,7 @@ namespace steemit { namespace chain { FC_ASSERT( is_valid_account_name( voter ), "Voter account name invalid" ); FC_ASSERT( is_valid_account_name( author ), "Author account name invalid" );\ FC_ASSERT( abs(weight) <= STEEMIT_100_PERCENT, "Weight is not a STEEMIT percentage" ); - FC_ASSERT( weight != 0, "Vote weight is 0" ); + //FC_ASSERT( weight != 0, "Vote weight is 0" ); } void transfer_operation::validate() const diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index d0bfaf895c..1eb7e45fb2 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -526,6 +526,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) { if( itr == comment_vote_idx.end() ) { + FC_ASSERT( o.weight != 0, "Vote weight cannot be 0" ); auto elapsed_seconds = (db().head_block_time() - voter.last_vote_time).to_seconds(); auto regenerated_power = ((STEEMIT_100_PERCENT - voter.voting_power) * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; auto current_power = std::min( int64_t(voter.voting_power + regenerated_power), int64_t(STEEMIT_100_PERCENT) ); @@ -608,6 +609,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) { else { FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_3 ), "Cannot undo votes until hardfork 3" ); + FC_ASSERT( o.weight == 0, "vote can only be removed, not modifed" ); db().modify( comment, [&]( comment_object& c ) { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index eb9f79b4a7..6610870842 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -645,6 +645,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( alice.last_vote_time == db.head_block_time() ); BOOST_REQUIRE_EQUAL( alice_comment.net_rshares.value, alice.vesting_shares.amount.value * ( old_voting_power - alice.voting_power ) / STEEMIT_100_PERCENT ); BOOST_REQUIRE( alice_comment.cashout_time == db.head_block_time() + fc::seconds( STEEMIT_CASHOUT_WINDOW_SECONDS ) ); + BOOST_REQUIRE( itr->rshares == alice.vesting_shares.amount.value * ( old_voting_power - alice.voting_power ) / STEEMIT_100_PERCENT ); BOOST_REQUIRE( itr != vote_idx.end() ); validate_database(); @@ -788,6 +789,70 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( db.get_comment( "alice", "foo" ).children_rshares2 == db.get_comment( "sam", "foo" ).children_rshares2 + old_rshares2 ); validate_database(); + + BOOST_TEST_MESSAGE( "--- Testing removing votes for hardfork 3" ); + db.set_hardfork( STEEMIT_HARDFORK_3 ); + + BOOST_TEST_MESSAGE( "--- Test failure when modifying a vote to a non-zero weight" ); + + auto alice_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, db.get_account( "alice" ).id ) ); + old_net_rshares = new_bob_comment.net_rshares.value; + auto old_abs_rshares = new_bob_comment.abs_rshares; + auto old_vote_weights = new_bob_comment.total_vote_weight; + auto vote_rshares = alice_bob_vote->rshares; + auto vote_weight = alice_bob_vote->weight; + + idump( (*alice_bob_vote) ); + + op.voter = "alice"; + op.author = "bob"; + op.permlink = "foo"; + op.weight = STEEMIT_1_PERCENT * 50; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( alice_private_key, db.get_chain_id() ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); + + BOOST_TEST_MESSAGE( "--- Test removing a positive vote" ); + + op.weight = 0; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( alice_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - vote_rshares ); + BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares - vote_rshares ); + BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_vote_weights - vote_weight ); + BOOST_REQUIRE( alice_bob_vote->weight == 0 ); + BOOST_REQUIRE( alice_bob_vote->rshares == 0 ); + + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test removing a negative vote" ); + + auto sam_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, db.get_account( "sam" ).id ) ); + old_net_rshares = new_bob_comment.net_rshares.value; + old_abs_rshares = new_bob_comment.abs_rshares; + old_vote_weights = new_bob_comment.total_vote_weight; + vote_rshares = sam_bob_vote->rshares; + vote_weight = sam_bob_vote->weight; + + op.voter = "sam"; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( sam_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - vote_rshares ); + BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares + vote_rshares ); + BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_vote_weights - vote_weight ); + BOOST_REQUIRE( sam_bob_vote->weight == 0 ); + BOOST_REQUIRE( sam_bob_vote->rshares == 0 ); + + validate_database(); } } FC_LOG_AND_RETHROW() From 73da310daea2436a4ddca129cc43db3d0b0d47ce Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 26 Apr 2016 14:17:26 -0400 Subject: [PATCH 03/20] Add check #22 --- tests/tests/operation_tests.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 6610870842..aeb04c4925 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -799,8 +799,10 @@ BOOST_AUTO_TEST_CASE( vote_apply ) old_net_rshares = new_bob_comment.net_rshares.value; auto old_abs_rshares = new_bob_comment.abs_rshares; auto old_vote_weights = new_bob_comment.total_vote_weight; + old_cashout_time = new_bob_comment.cashout_time; auto vote_rshares = alice_bob_vote->rshares; auto vote_weight = alice_bob_vote->weight; + auto alice_vote_power = db.get_account( "alice" ).voting_power; idump( (*alice_bob_vote) ); @@ -826,8 +828,10 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - vote_rshares ); BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares - vote_rshares ); BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_vote_weights - vote_weight ); + BOOST_REQUIRE( new_bob_comment.cashout_time == old_cashout_time ); BOOST_REQUIRE( alice_bob_vote->weight == 0 ); BOOST_REQUIRE( alice_bob_vote->rshares == 0 ); + BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_vote_power ); validate_database(); @@ -839,6 +843,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) old_vote_weights = new_bob_comment.total_vote_weight; vote_rshares = sam_bob_vote->rshares; vote_weight = sam_bob_vote->weight; + auto sam_vote_power = db.get_account( "sam" ).voting_power; op.voter = "sam"; tx.operations.clear(); @@ -849,8 +854,10 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - vote_rshares ); BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares + vote_rshares ); BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_vote_weights - vote_weight ); + BOOST_REQUIRE( new_bob_comment.cashout_time == old_cashout_time ); BOOST_REQUIRE( sam_bob_vote->weight == 0 ); BOOST_REQUIRE( sam_bob_vote->rshares == 0 ); + BOOST_REQUIRE( db.get_account( "sam" ).voting_power == sam_voting_power ); validate_database(); } From a59a8c3de3af93eb2eebd89812bcf8981d6dfec6 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Thu, 5 May 2016 16:54:37 -0400 Subject: [PATCH 04/20] Obligatory incremental commit --- libraries/chain/database.cpp | 15 +++++- libraries/chain/steem_evaluator.cpp | 5 +- .../plugins/debug_node/debug_node_api.cpp | 19 +++++-- .../plugins/debug_node/debug_node_api.hpp | 2 +- python_scripts/steemdebugnode/debugnode.py | 50 ++++++++++++------- python_scripts/tests/debug_hardforks.py | 13 +++-- 6 files changed, 73 insertions(+), 31 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 3824bf9c24..640442c05c 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1314,6 +1314,8 @@ void database::adjust_total_payout( const comment_object& cur, const asset& sbd_ * @recursively pays out parent posts */ void database::cashout_comment_helper( const comment_object& cur, const comment_object& origin, asset vesting_steem_reward, asset sbd_reward ) { + try + { const auto& author = get_account( cur.author ); if( cur.parent_author.size() ) { auto parent_vesting_steem_reward = vesting_steem_reward; @@ -1358,6 +1360,7 @@ void database::cashout_comment_helper( const comment_object& cur, const comment_ push_applied_operation( comment_reward_operation( cur.author, cur.permlink, origin.author, origin.permlink, sbd_created, vest_created ) ); adjust_total_payout( cur, sbd_created + to_sbd( vesting_steem_reward ) ); } + } FC_CAPTURE_LOG_AND_RETHROW( (cur) ); } /** @@ -1376,6 +1379,8 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar 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 + try + { u256 weight( itr->weight ); auto claim = static_cast((max_rewards.value * weight) / total_weight); if( claim > 1 ) // min_amt is non-zero satoshis @@ -1384,6 +1389,7 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar 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 ) ); } + } FC_CAPTURE_LOG_AND_RETHROW( (*itr) ) ++itr; } if( max_rewards.value - unclaimed_rewards.value ) @@ -1408,6 +1414,8 @@ void database::process_comment_cashout() { auto current = cidx.begin(); //auto end = cidx.lower_bound( head_block_time() ); while( current != cidx.end() && current->cashout_time <= head_block_time() ) { + try + { const auto& cur = *current; ++current; asset sbd_created(0,SBD_SYMBOL); asset vest_created(0,VESTS_SYMBOL); @@ -1461,6 +1469,7 @@ void database::process_comment_cashout() { ++vote_itr; remove(cur_vote); } + } FC_CAPTURE_LOG_AND_RETHROW( (*current) ); } } @@ -1633,6 +1642,8 @@ asset database::to_steem( const asset& sbd )const { * redeemed. */ share_type database::claim_rshare_reward( share_type rshares ) { + try + { FC_ASSERT( rshares > 0 ); const auto& props = get_dynamic_global_properties(); @@ -1654,7 +1665,7 @@ share_type database::claim_rshare_reward( share_type rshares ) { modify( props, [&]( dynamic_global_property_object& p ){ p.total_reward_fund_steem.amount -= payout; }); - + } FC_CAPTURE_LOG_AND_RETHROW( (rshares) ) return payout; } @@ -1872,7 +1883,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(); } diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index a1d48d5838..39c102a0df 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace steemit { namespace chain { using fc::uint128_t; @@ -196,7 +198,7 @@ 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 ) + if( parent ) cso.parent_comment_id = parent->id; cso.category_id = cat->id; cso.author_id = auth.get_id(); @@ -537,7 +539,6 @@ void vote_evaluator::do_apply( const vote_operation& o ) FC_ASSERT( abs_rshares > 0 ); - db().modify( comment, [&]( comment_object& c ){ c.net_rshares += rshares; c.abs_rshares += abs_rshares; diff --git a/libraries/plugins/debug_node/debug_node_api.cpp b/libraries/plugins/debug_node/debug_node_api.cpp index a866b339f2..6068feaf76 100644 --- a/libraries/plugins/debug_node/debug_node_api.cpp +++ b/libraries/plugins/debug_node/debug_node_api.cpp @@ -23,7 +23,7 @@ class debug_node_api_impl public: debug_node_api_impl( steemit::app::application& _app ); - uint32_t debug_push_blocks( const std::string& src_filename, uint32_t count ); + uint32_t debug_push_blocks( const std::string& src_filename, uint32_t count, bool skip_validate_invariants ); uint32_t debug_generate_blocks( const std::string& debug_key, uint32_t count ); uint32_t debug_generate_blocks_until( const std::string& debug_key, const fc::time_point_sec& head_block_time, bool generate_sparsely ); void debug_update_object( const fc::variant_object& update ); @@ -40,7 +40,7 @@ debug_node_api_impl::debug_node_api_impl( steemit::app::application& _app ) : ap {} -uint32_t debug_node_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count ) +uint32_t debug_node_api_impl::debug_push_blocks( const std::string& src_filename, uint32_t count, bool skip_validate_invariants ) { if( count == 0 ) return 0; @@ -50,9 +50,16 @@ uint32_t debug_node_api_impl::debug_push_blocks( const std::string& src_filename if( fc::is_directory( src_path ) ) { ilog( "Loading ${n} from block_database ${fn}", ("n", count)("fn", src_filename) ); + idump( (src_filename)(count)(skip_validate_invariants) ); steemit::chain::block_database bdb; bdb.open( src_path ); uint32_t first_block = db->head_block_num()+1; + uint32_t skip_flags = steemit::chain::database::skip_nothing; + if( skip_validate_invariants ) + { + skip_flags = skip_flags | steemit::chain::database::skip_validate_invariants; + ilog( "Skipping invariante check" ); + } for( uint32_t i=0; i block = bdb.fetch_by_number( first_block+i ); @@ -63,7 +70,7 @@ uint32_t debug_node_api_impl::debug_push_blocks( const std::string& src_filename } try { - db->push_block( *block ); + db->push_block( *block, skip_flags ); } catch( const fc::exception& e ) { @@ -146,6 +153,8 @@ uint32_t debug_node_api_impl::debug_generate_blocks_until( const std::string& de db->generate_block( scheduled_time, scheduled_witness_name, *debug_private_key, steemit::chain::database::skip_nothing ); new_blocks++; + + FC_ASSERT( head_block_time.sec_since_epoch() - db->head_block_time().sec_since_epoch() < STEEMIT_BLOCK_INTERVAL, "", ("desired_time", head_block_time)("db->head_block_time()",db->head_block_time()) ); } } else @@ -199,9 +208,9 @@ debug_node_api::debug_node_api( steemit::app::application& app ) void debug_node_api::on_api_startup() {} -uint32_t debug_node_api::debug_push_blocks( std::string source_filename, uint32_t count ) +uint32_t debug_node_api::debug_push_blocks( std::string source_filename, uint32_t count, bool skip_validate_invariants ) { - return my->debug_push_blocks( source_filename, count ); + return my->debug_push_blocks( source_filename, count, skip_validate_invariants ); } uint32_t debug_node_api::debug_generate_blocks( std::string debug_key, uint32_t count ) diff --git a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp index f9faf2619d..d99c4f14ea 100644 --- a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp +++ b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp @@ -27,7 +27,7 @@ class debug_node_api /** * Push blocks from existing database. */ - uint32_t debug_push_blocks( std::string src_filename, uint32_t count ); + uint32_t debug_push_blocks( std::string src_filename, uint32_t count, bool skip_validate_invariants = false ); /** * Generate blocks locally. diff --git a/python_scripts/steemdebugnode/debugnode.py b/python_scripts/steemdebugnode/debugnode.py index 3b78e46155..01107b2174 100644 --- a/python_scripts/steemdebugnode/debugnode.py +++ b/python_scripts/steemdebugnode/debugnode.py @@ -1,5 +1,7 @@ -import datetime, json, logging +import json, logging +from datetime import datetime +from datetime import timezone from os import devnull from pathlib import Path from signal import SIGINT, SIGTERM @@ -13,7 +15,7 @@ class DebugNode( object ): """ Wraps the steemd debug node plugin for easier automated testing of the Steem Network""" - def __init__( self, steemd, data_dir, plugins=[], apis=[], steemd_stdout=None, steemd_stderr=None ): + def __init__( self, steemd, data_dir, plugins=[], apis=[], steemd_out=None, steemd_err=None ): """ Creates a steemd debug node. It can be ran by using 'with debug_node:' @@ -56,15 +58,15 @@ def __init__( self, steemd, data_dir, plugins=[], apis=[], steemd_stdout=None, s self.apis = apis self._FNULL = open( devnull, 'w' ) - if( steemd_stdout != None ): - self.steemd_stdout = steemd_stdout + if( steemd_out != None ): + self.steemd_out = steemd_out else: - self.steemd_stdout = self._FNULL + self.steemd_out = self._FNULL - if( steemd_stderr != None ): - self.steemd_stderr = steemd_stderr + if( steemd_err != None ): + self.steemd_err = steemd_err else: - self.steemd_stderr = self._FNULL + self.steemd_err = self._FNULL self._debug_key = '5JHNbFNDg834SFj8CMArV6YW7td4zrPzXveqTfaShmYVuYNeK69' self._steemd_lock = Lock() @@ -79,7 +81,7 @@ def __enter__( self ): config.touch() config.write_text( self._get_config() ) - self._steemd_process = Popen( [ str( self._steemd_bin ), '--data-dir="' + str( self._temp_data_dir.name ) + '"' ], stdout=self._FNULL, stderr=self._FNULL ) + self._steemd_process = Popen( [ str( self._steemd_bin ), '--data-dir="' + str( self._temp_data_dir.name ) + '"' ], stdout=self.steemd_out, stderr=self.steemd_err ) self._steemd_process.poll() sleep( 5 ) if( not self._steemd_process.returncode ): @@ -122,7 +124,7 @@ def _get_config( self ): + "public-api = database_api login_api debug_node_api " + " ".join( self.apis ) + "\n" - def debug_push_blocks( self, count=0 ): + def debug_push_blocks( self, count=0, skip_validate_invariants=False ): """ Push count blocks from an existing chain. There is no guarantee pushing blocks will work depending on set hardforks, or generated blocks @@ -136,13 +138,17 @@ def debug_push_blocks( self, count=0 ): int: The number of blocks actually pushed. """ num_blocks = 0 + skip_validate_invariants_str = "false" + if( skip_validate_invariants ): + skip_validate_invariants_str = "true" + if( count == 0 ): ret = 10000 while( ret == 10000 ): - ret = self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_push_blocks",["' + str( self._block_dir ) + '", 10000]], "id": 1}' ) ) + ret = self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_push_blocks",["' + str( self._block_dir ) + '", 10000,"' + skip_validate_invariants_str + '"]], "id": 1}' ) ) num_blocks += ret else: - ret = self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_push_blocks",["' + str( self._block_dir ) + '",' + str( count ) + ']], "id": 1}' ) ) + ret = self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_push_blocks",["' + str( self._block_dir ) + '",' + str( count ) + ',"' + skip_validate_invariants_str + '"]], "id": 1}' ) ) num_blocks += ret return num_blocks @@ -167,7 +173,7 @@ def debug_generate_blocks( self, count ): return self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_generate_blocks",["' + self._debug_key + '",' + str( count ) + ']], "id": 1}' ) ) - def debug_generate_blocks_until( self, time, generate_sparsely=True ): + def debug_generate_blocks_until( self, timestamp, generate_sparsely=True ): """ Generate block up until a head block time rather than a specific number of blocks. As with `debug_generate_blocks` all blocks will be empty unless there were pending transactions. @@ -177,7 +183,7 @@ def debug_generate_blocks_until( self, time, generate_sparsely=True ): `get_dev_key steem debug`. Do not use this key on the live chain for any reason. args: - time -- The desired new head block time. This is a UTC Timestmap. + time -- The desired new head block time. This is a POSIX Timestmap. generate_sparsely -- True if you wish to skip all intermediate blocks between the current head block time and the desired head block time. This is useful to trigger events, such as payouts and bandwidth updates, without generating blocks. However, many automatic chain @@ -188,9 +194,19 @@ def debug_generate_blocks_until( self, time, generate_sparsely=True ): (time, int): A tuple including the new head block time and the number of blocks that were generated. """ - if( not instance( time, datetime ) ): - raise ValueError( "Time must be a datetime object" ) - self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_generate_blocks_until",["' + self._debug_key + '",' + str( time ) + ']], "id": 1}' ) ) + if( not isinstance( timestamp, int ) ): + raise ValueError( "Time must be a int" ) + generate_sparsely_str = "true" + if( not generate_sparsely ): + generate_sparsely_str = "false" + + iso_string = datetime.fromtimestamp( timestamp, timezone.utc ).isoformat().split( '+' )[0].split( '-' ) + if( len( iso_string ) == 4 ): + iso_string = iso_string[:-1] + iso_string = '-'.join( iso_string ) + + print( iso_string ) + return self._rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [2,"debug_generate_blocks_until",["' + self._debug_key + '","' + iso_string + '","' + generate_sparsely_str + '"]], "id": 1}' ) ) def debug_set_hardfork( self, hardfork_id ): diff --git a/python_scripts/tests/debug_hardforks.py b/python_scripts/tests/debug_hardforks.py index 6691121dee..4383c80145 100644 --- a/python_scripts/tests/debug_hardforks.py +++ b/python_scripts/tests/debug_hardforks.py @@ -47,7 +47,7 @@ def main( ): if( not data_dir.is_dir() ): print( 'Error: data_dir is not a directory' ) - debug_node = DebugNode( str( steemd ), str( data_dir ) ) + debug_node = DebugNode( str( steemd ), str( data_dir ), steemd_err=sys.stderr ) with debug_node : @@ -62,8 +62,13 @@ def run_steemd_tests( debug_node ): from steemapi.steemnoderpc import SteemNodeRPC try: - print( "Playing blockchain..." ) - blocks = debug_node.debug_push_blocks( 0 ) + print( 'Replaying blocks...', ) + sys.stdout.flush() + total_blocks = 0 + while( total_blocks % 100000 == 0 ): + total_blocks += debug_node.debug_push_blocks( 100000, skip_validate_invariants=True ) + print( 'Blocks Replayed: ' + str( total_blocks ) ) + sys.stdout.flush() print( "Setting the hardfork now" ) # TODO: Grab most recent hardfork num from build directory sys.stdout.flush() @@ -77,7 +82,7 @@ def run_steemd_tests( debug_node ): sys.stdout.flush() rpc = SteemNodeRPC( 'ws://127.0.0.1:8090', '', '' ) block_producers = {} - for i in range( blocks + 1 , blocks + 5001 ): + for i in range( total_blocks + 1 , total_blocks + 5001 ): ret = rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [0,"get_block",[' + str( i ) + ']], "id":4}' ) ) if( ret[ "witness" ] in block_producers ): block_producers[ ret[ "witness" ] ] += 1 From 04c2f82b03bab5554aca7a15849c1a0647b1f04c Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Thu, 5 May 2016 18:04:05 -0400 Subject: [PATCH 05/20] End of day commit. --- libraries/chain/database.cpp | 24 +++++++++++++++++----- python_scripts/steemdebugnode/debugnode.py | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 640442c05c..d1545f1810 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1374,10 +1374,23 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar u256 total_weight( c.total_vote_weight ); share_type unclaimed_rewards = max_rewards; + /* + const auto& idx = my->_db.get_index_type().indices().get< by_comment_voter >(); + comment_id_type cid(comment.id); + auto itr = idx.lower_bound( cid ); + while( itr != idx.end() && itr->comment == cid ) + { + const auto& vo = itr->voter(my->_db); + result.push_back(vote_state{vo.name,itr->weight}); + ++itr; + } + */ + const auto& cvidx = get_index_type().indices().get(); - 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 ) { + auto itr = cvidx.lower_bound( c.id ); + auto start = itr; + //auto end = cvidx.lower_bound( boost::make_tuple( c.id, uint64_t(0), account_id_type() ) ); + while( itr != cvidx.end() && itr->comment == c.id ) { // TODO: Add minimum curation pay limit try { @@ -1389,7 +1402,7 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar 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 ) ); } - } FC_CAPTURE_LOG_AND_RETHROW( (*itr) ) + } FC_CAPTURE_LOG_AND_RETHROW( (c)(*itr)(*start)/*(*end)*/ ) ++itr; } if( max_rewards.value - unclaimed_rewards.value ) @@ -1665,8 +1678,9 @@ share_type database::claim_rshare_reward( share_type rshares ) { modify( props, [&]( dynamic_global_property_object& p ){ p.total_reward_fund_steem.amount -= payout; }); - } FC_CAPTURE_LOG_AND_RETHROW( (rshares) ) return payout; + } FC_CAPTURE_LOG_AND_RETHROW( (rshares) ) + return 0; } const dynamic_global_property_object&database::get_dynamic_global_properties() const diff --git a/python_scripts/steemdebugnode/debugnode.py b/python_scripts/steemdebugnode/debugnode.py index 01107b2174..1b01990128 100644 --- a/python_scripts/steemdebugnode/debugnode.py +++ b/python_scripts/steemdebugnode/debugnode.py @@ -85,7 +85,7 @@ def __enter__( self ): self._steemd_process.poll() sleep( 5 ) if( not self._steemd_process.returncode ): - self._rpc = SteemNodeRPC( 'ws://127.0.0.1:8090', '', '' ) + self._rpc = SteemNodeRPC( 'ws://127.0.0.1:8095', '', '' ) else: raise Exception( "steemd did not start properly..." ) @@ -119,7 +119,7 @@ def __exit__( self, exc, value, tb ): def _get_config( self ): return "# no seed-node in config file or command line\n" \ + "p2p-endpoint = 127.0.0.1:2001 # bind to localhost to prevent remote p2p nodes from connecting to us\n" \ - + "rpc-endpoint = 127.0.0.1:8090 # bind to localhost to secure RPC API access\n" \ + + "rpc-endpoint = 127.0.0.1:8095 # bind to localhost to secure RPC API access\n" \ + "enable-plugin = witness debug_node " + " ".join( self.plugins ) + "\n" \ + "public-api = database_api login_api debug_node_api " + " ".join( self.apis ) + "\n" From 32b98b42efb8190628bdb050a7bd22e1e32c6831 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Fri, 6 May 2016 11:21:21 -0400 Subject: [PATCH 06/20] Incremental commit --- libraries/chain/database.cpp | 39 ++++++++++++------------------ libraries/chain/protocol/asset.cpp | 5 ++-- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index d1545f1810..a3cec76f0c 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -826,7 +826,7 @@ try { adjust_balance( to_account, sbd ); adjust_supply( -steem ); adjust_supply( sbd ); - + validate_invariants(); return sbd; } else { adjust_balance( to_account, steem ); @@ -1360,6 +1360,7 @@ void database::cashout_comment_helper( const comment_object& cur, const comment_ push_applied_operation( comment_reward_operation( cur.author, cur.permlink, origin.author, origin.permlink, sbd_created, vest_created ) ); adjust_total_payout( cur, sbd_created + to_sbd( vesting_steem_reward ) ); } + validate_invariants(); } FC_CAPTURE_LOG_AND_RETHROW( (cur) ); } @@ -1374,18 +1375,6 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar u256 total_weight( c.total_vote_weight ); share_type unclaimed_rewards = max_rewards; - /* - const auto& idx = my->_db.get_index_type().indices().get< by_comment_voter >(); - comment_id_type cid(comment.id); - auto itr = idx.lower_bound( cid ); - while( itr != idx.end() && itr->comment == cid ) - { - const auto& vo = itr->voter(my->_db); - result.push_back(vote_state{vo.name,itr->weight}); - ++itr; - } - */ - const auto& cvidx = get_index_type().indices().get(); auto itr = cvidx.lower_bound( c.id ); auto start = itr; @@ -1410,7 +1399,7 @@ share_type database::pay_curators( const comment_object& c, share_type max_rewar { p.total_reward_fund_steem += unclaimed_rewards; }); - + validate_invariants(); return unclaimed_rewards; } @@ -1482,6 +1471,8 @@ void database::process_comment_cashout() { ++vote_itr; remove(cur_vote); } + + validate_invariants(); } FC_CAPTURE_LOG_AND_RETHROW( (*current) ); } } @@ -2647,7 +2638,7 @@ void database::set_hardfork( uint32_t hardfork, bool process_now ) */ void database::validate_invariants()const { - const auto& db = *this; + //const auto& db = *this; try { // const auto& account_idx = get_index_type< account_index >().indices().get< by_id >(); @@ -2657,7 +2648,7 @@ void database::validate_invariants()const asset total_vesting = asset( 0, VESTS_SYMBOL ); share_type total_vsf_votes = share_type( 0 ); - auto gpo = db.get_dynamic_global_properties(); + auto gpo = get_dynamic_global_properties(); /// verify no witness has too many votes const auto& witness_idx = get_index_type< witness_index >().indices(); @@ -2672,7 +2663,7 @@ void database::validate_invariants()const total_vsf_votes += itr->proxy == STEEMIT_PROXY_TO_SELF_ACCOUNT ? itr->proxied_vsf_votes + itr->vesting_shares.amount : 0; } - const auto& convert_request_idx = db.get_index_type< convert_index >().indices(); + const auto& convert_request_idx = get_index_type< convert_index >().indices(); for( auto itr = convert_request_idx.begin(); itr != convert_request_idx.end(); itr++ ) { @@ -2684,7 +2675,7 @@ void database::validate_invariants()const FC_ASSERT( !"Encountered illegal symbol in convert_request_object" ); } - const auto& limit_order_idx = db.get_index_type< limit_order_index >().indices(); + const auto& limit_order_idx = get_index_type< limit_order_index >().indices(); for( auto itr = limit_order_idx.begin(); itr != limit_order_idx.end(); itr++ ) { @@ -2701,7 +2692,7 @@ void database::validate_invariants()const fc::uint128_t total_rshares2; fc::uint128_t total_children_rshares2; - const auto& comment_idx = db.get_index_type< comment_index >().indices(); + const auto& comment_idx = get_index_type< comment_index >().indices(); for( auto itr = comment_idx.begin(); itr != comment_idx.end(); itr++ ) { @@ -2723,11 +2714,11 @@ void database::validate_invariants()const FC_ASSERT( total_rshares2 == total_children_rshares2, "", ("total_rshares2", total_rshares2)("total_children_rshares2",total_children_rshares2)); FC_ASSERT( gpo.virtual_supply >= gpo.current_supply ); - if ( !db.get_feed_history().current_median_history.is_null() ) - FC_ASSERT( gpo.current_sbd_supply * db.get_feed_history().current_median_history + gpo.current_supply - == gpo.virtual_supply ); + /*if ( !get_feed_history().current_median_history.is_null() ) + FC_ASSERT( gpo.current_sbd_supply * get_feed_history().current_median_history + gpo.current_supply + == gpo.virtual_supply, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("get_feed_history().current_median_history",get_feed_history().current_median_history)("gpo.current_supply",gpo.current_supply)("gpo.virtual_supply",gpo.virtual_supply) );*/ } - FC_CAPTURE_LOG_AND_RETHROW( (db.head_block_num()) ); + FC_CAPTURE_LOG_AND_RETHROW( (head_block_num()) ); } void database::perform_vesting_share_split( uint32_t magnitude ) @@ -2771,7 +2762,7 @@ void database::perform_vesting_share_split( uint32_t magnitude ) for( const auto& vote : vote_idx ) { modify( vote, [&]( comment_vote_object& cv ) { - cv.weight = ( cv.weight * magnitude ) * magnitude; + cv.weight = cv.weight * magnitude ; }); } diff --git a/libraries/chain/protocol/asset.cpp b/libraries/chain/protocol/asset.cpp index b3e3d52e26..dce48e334c 100644 --- a/libraries/chain/protocol/asset.cpp +++ b/libraries/chain/protocol/asset.cpp @@ -127,15 +127,14 @@ namespace steemit { namespace chain { { FC_ASSERT( b.base.amount.value > 0 ); uint128_t result = (uint128_t(a.amount.value) * b.quote.amount.value)/b.base.amount.value; - FC_ASSERT( result <= uint64_t(-1) ); + FC_ASSERT( result.hi == 0 ); return asset( result.to_uint64(), b.quote.symbol ); } else if( a.symbol_name() == b.quote.symbol_name() ) { FC_ASSERT( b.quote.amount.value > 0 ); uint128_t result = (uint128_t(a.amount.value) * b.base.amount.value)/b.quote.amount.value; - //FC_ASSERT( result <= STEEMIT_MAX_SHARE_SUPPLY, "${result}", ("result",result)("max",STEEMIT_MAX_SHARE_SUPPLY)("asset",a)("price",b) ); - FC_ASSERT( result <= uint64_t(-1) ); + FC_ASSERT( result.hi == 0 ); return asset( result.to_uint64(), b.base.symbol ); } FC_THROW_EXCEPTION( fc::assert_exception, "invalid asset * price", ("asset",a)("price",b) ); From f95dfa36830c8fdc9683385678bbebcca64aa40f Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 10 May 2016 08:58:09 -0400 Subject: [PATCH 07/20] Progress... --- .../plugins/debug_node/debug_node_api.cpp | 51 +++++++++++-------- .../plugins/debug_node/debug_node_api.hpp | 14 +++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/libraries/plugins/debug_node/debug_node_api.cpp b/libraries/plugins/debug_node/debug_node_api.cpp index b3e245cfb4..dd87703a91 100644 --- a/libraries/plugins/debug_node/debug_node_api.cpp +++ b/libraries/plugins/debug_node/debug_node_api.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -26,6 +27,8 @@ class debug_node_api_impl uint32_t debug_push_blocks( const std::string& src_filename, uint32_t count, bool skip_validate_invariants ); uint32_t debug_generate_blocks( const std::string& debug_key, uint32_t count ); uint32_t debug_generate_blocks_until( const std::string& debug_key, const fc::time_point_sec& head_block_time, bool generate_sparsely ); + chain::signed_block debug_pop_block(); + void debug_push_block( const chain::signed_block& block ); void debug_update_object( const fc::variant_object& update ); //void debug_save_db( std::string db_path ); void debug_stream_json_objects( const std::string& filename ); @@ -129,8 +132,8 @@ uint32_t debug_node_api_impl::debug_generate_blocks_until( const std::string& de { auto new_slot = db->get_slot_at_time( head_block_time ); - if( new_slot <= 1 ) - return debug_generate_blocks( debug_key, new_slot ); + if( new_slot == 0 ) + return 0; std::shared_ptr< debug_node_plugin > debug_plugin = get_plugin(); fc::optional debug_private_key = graphene::utilities::wif_to_key( debug_key ); @@ -155,24 +158,6 @@ uint32_t debug_node_api_impl::debug_generate_blocks_until( const std::string& de db->generate_block( scheduled_time, scheduled_witness_name, *debug_private_key, steemit::chain::database::skip_nothing ); new_blocks++; - /*scheduled_witness_name = db->get_scheduled_witness( 1 ); - scheduled_time = db->get_slot_time( 1 ); - const auto& next_scheduled_witness = db->get_witness( scheduled_witness_name ); - scheduled_key = next_scheduled_witness.signing_key; - - wlog( "scheduled key is: ${sk} dbg key is: ${dk}", ("sk", scheduled_key)("dk", debug_public_key) ); - - if( scheduled_key != debug_public_key ) - { - wlog( "Modified key for witness ${w}", ("w", scheduled_witness_name) ); - fc::mutable_variant_object update; - update("_action", "update")("id", next_scheduled_witness.id)("signing_key", debug_public_key); - debug_plugin->debug_update( update ); - } - - db->generate_block( scheduled_time, scheduled_witness_name, *debug_private_key, steemit::chain::database::skip_nothing ); - new_blocks++;*/ - FC_ASSERT( head_block_time.sec_since_epoch() - db->head_block_time().sec_since_epoch() < STEEMIT_BLOCK_INTERVAL, "", ("desired_time", head_block_time)("db->head_block_time()",db->head_block_time()) ); } else @@ -184,6 +169,22 @@ uint32_t debug_node_api_impl::debug_generate_blocks_until( const std::string& de return new_blocks; } +chain::signed_block debug_node_api_impl::debug_pop_block() +{ + std::shared_ptr< steemit::chain::database > db = app.chain_database(); + + fc::optional< chain::signed_block > head_block = db->fetch_block_by_id( db->head_block_id() ); + FC_ASSERT( head_block.valid() ); + db->pop_block(); + + return *head_block; +} + +void debug_node_api_impl::debug_push_block( const chain::signed_block& block ) +{ + app.chain_database()->push_block( block ); +} + void debug_node_api_impl::debug_update_object( const fc::variant_object& update ) { get_plugin()->debug_update( update ); @@ -241,6 +242,16 @@ uint32_t debug_node_api::debug_generate_blocks_until( std::string debug_key, fc: return my->debug_generate_blocks_until( debug_key, head_block_time, generate_sparsely ); } +chain::signed_block debug_node_api::debug_pop_block() +{ + return my->debug_pop_block(); +} + +void debug_node_api::debug_push_block( chain::signed_block& block ) +{ + my->debug_push_block( block ); +} + void debug_node_api::debug_update_object( fc::variant_object update ) { my->debug_update_object( update ); diff --git a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp index d99c4f14ea..dfefdfcb09 100644 --- a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp +++ b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp @@ -7,6 +7,8 @@ #include #include +#include + namespace steemit { namespace app { class application; } } @@ -39,6 +41,16 @@ class debug_node_api */ uint32_t debug_generate_blocks_until( std::string debug_key, fc::time_point_sec head_block_time, bool generate_sparsely = true ); + /* + * Pop a block from the blockchain, returning it + */ + chain::signed_block debug_pop_block(); + + /* + * Push an already constructed block onto the blockchain. For use with pop_block to traverse state block by block. + */ + void debug_push_block( chain::signed_block& block ); + /** * Directly manipulate database objects (will undo and re-apply last block with new changes post-applied). */ @@ -78,6 +90,8 @@ FC_API(steemit::plugin::debug_node::debug_node_api, (debug_push_blocks) (debug_generate_blocks) (debug_generate_blocks_until) + (debug_pop_block) + (debug_push_block) (debug_update_object) (debug_stream_json_objects) (debug_stream_json_objects_flush) From d8bccc296a93555da40680d09b6ca755535891b3 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 10 May 2016 10:05:41 -0400 Subject: [PATCH 08/20] Fix build --- .../plugins/debug_node/debug_node_api.cpp | 23 ++++++++----------- .../plugins/debug_node/debug_node_api.hpp | 7 +++--- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/libraries/plugins/debug_node/debug_node_api.cpp b/libraries/plugins/debug_node/debug_node_api.cpp index dd87703a91..5b5afc9d6c 100644 --- a/libraries/plugins/debug_node/debug_node_api.cpp +++ b/libraries/plugins/debug_node/debug_node_api.cpp @@ -27,8 +27,8 @@ class debug_node_api_impl uint32_t debug_push_blocks( const std::string& src_filename, uint32_t count, bool skip_validate_invariants ); uint32_t debug_generate_blocks( const std::string& debug_key, uint32_t count ); uint32_t debug_generate_blocks_until( const std::string& debug_key, const fc::time_point_sec& head_block_time, bool generate_sparsely ); - chain::signed_block debug_pop_block(); - void debug_push_block( const chain::signed_block& block ); + fc::optional< steemit::chain::signed_block > debug_pop_block(); + //void debug_push_block( const steemit::chain::signed_block& block ); void debug_update_object( const fc::variant_object& update ); //void debug_save_db( std::string db_path ); void debug_stream_json_objects( const std::string& filename ); @@ -169,21 +169,16 @@ uint32_t debug_node_api_impl::debug_generate_blocks_until( const std::string& de return new_blocks; } -chain::signed_block debug_node_api_impl::debug_pop_block() +fc::optional< steemit::chain::signed_block > debug_node_api_impl::debug_pop_block() { std::shared_ptr< steemit::chain::database > db = app.chain_database(); - - fc::optional< chain::signed_block > head_block = db->fetch_block_by_id( db->head_block_id() ); - FC_ASSERT( head_block.valid() ); - db->pop_block(); - - return *head_block; + return db->fetch_block_by_number( db->head_block_num() ); } -void debug_node_api_impl::debug_push_block( const chain::signed_block& block ) +/*void debug_node_api_impl::debug_push_block( const steemit::chain::signed_block& block ) { app.chain_database()->push_block( block ); -} +}*/ void debug_node_api_impl::debug_update_object( const fc::variant_object& update ) { @@ -242,15 +237,15 @@ uint32_t debug_node_api::debug_generate_blocks_until( std::string debug_key, fc: return my->debug_generate_blocks_until( debug_key, head_block_time, generate_sparsely ); } -chain::signed_block debug_node_api::debug_pop_block() +fc::optional< steemit::chain::signed_block > debug_node_api::debug_pop_block() { return my->debug_pop_block(); } -void debug_node_api::debug_push_block( chain::signed_block& block ) +/*void debug_node_api::debug_push_block( steemit::chain::signed_block& block ) { my->debug_push_block( block ); -} +}*/ void debug_node_api::debug_update_object( fc::variant_object update ) { diff --git a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp index dfefdfcb09..3107a8c1d8 100644 --- a/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp +++ b/libraries/plugins/debug_node/include/steemit/plugins/debug_node/debug_node_api.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -44,12 +45,12 @@ class debug_node_api /* * Pop a block from the blockchain, returning it */ - chain::signed_block debug_pop_block(); + fc::optional< steemit::chain::signed_block > debug_pop_block(); /* * Push an already constructed block onto the blockchain. For use with pop_block to traverse state block by block. */ - void debug_push_block( chain::signed_block& block ); + //void debug_push_block( steemit::chain::signed_block& block ); /** * Directly manipulate database objects (will undo and re-apply last block with new changes post-applied). @@ -91,7 +92,7 @@ FC_API(steemit::plugin::debug_node::debug_node_api, (debug_generate_blocks) (debug_generate_blocks_until) (debug_pop_block) - (debug_push_block) + //(debug_push_block) (debug_update_object) (debug_stream_json_objects) (debug_stream_json_objects_flush) From 0749bddd82c9c1b30fd7043aa857cff96d555937 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Tue, 10 May 2016 13:50:25 -0400 Subject: [PATCH 09/20] Finish testing. --- libraries/app/database_api.cpp | 10 +++++----- libraries/app/include/steemit/app/database_api.hpp | 5 ++++- libraries/chain/database.cpp | 14 -------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 4cf76bd3ff..4840b4ec69 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -755,7 +755,7 @@ void database_api::set_pending_payout( discussion& d )const if( props.total_reward_shares2 > 0 ){ int64_t abs_net_rshares = llabs(d.net_rshares.value); - + u256 r2 = to256(abs_net_rshares); r2 *= r2; r2 *= pot.amount.value; @@ -809,7 +809,7 @@ vector database_api::get_discussions_by_last_update( string start_pa auto itr = last_update_idx.begin(); - if( start_permlink.size() ) + if( start_permlink.size() ) itr = last_update_idx.iterator_to( my->_db.get_comment( start_parent_author, start_permlink ) ); else if( start_parent_author.size() ) { itr = last_update_idx.lower_bound( boost::make_tuple( start_parent_author, time_point_sec::maximum(), object_id_type() ) ); @@ -845,7 +845,7 @@ vector database_api::get_discussions_by_created( string start_auth, vector database_api::get_discussions_by_cashout_time( string start_auth, string start_permlink, uint32_t limit )const { const auto& cashout_time_idx = my->_db.get_index_type< comment_index >().indices().get< by_cashout_time >(); - + idump( (limit) ); auto itr = cashout_time_idx.begin(); if( start_auth.size() ) @@ -1065,7 +1065,7 @@ vector database_api::get_active_witnesses()const { return wso.current_shuffled_witnesses; } -vector database_api::get_discussions_by_author_before_date( +vector database_api::get_discussions_by_author_before_date( string author, string start_permlink, time_point_sec before_date, uint32_t limit )const { try { vector result; @@ -1074,7 +1074,7 @@ vector database_api::get_discussions_by_author_before_date( int count = 0; const auto& didx = my->_db.get_index_type().indices().get(); - if( before_date == time_point_sec() ) + if( before_date == time_point_sec() ) before_date = time_point_sec::maximum(); auto itr = didx.lower_bound( boost::make_tuple( author, time_point_sec::maximum() ) ); diff --git a/libraries/app/include/steemit/app/database_api.hpp b/libraries/app/include/steemit/app/database_api.hpp index 44af36e85e..87f2c35605 100755 --- a/libraries/app/include/steemit/app/database_api.hpp +++ b/libraries/app/include/steemit/app/database_api.hpp @@ -312,7 +312,7 @@ class database_api /** * This method is used to fetch all posts/comments by start_author that occur after before_date and start_permlink with up to limit being returned. * - * If start_permlink is empty then only before_date will be considered. If both are specified the eariler to the two metrics will be used. This + * If start_permlink is empty then only before_date will be considered. If both are specified the eariler to the two metrics will be used. This * should allow easy pagination. */ vector get_discussions_by_author_before_date( string author, string start_permlink, time_point_sec before_date, uint32_t limit )const; @@ -404,6 +404,9 @@ FC_API(steemit::app::database_api, (get_discussions_in_category_by_last_update) (get_discussions_in_category_by_created) (get_discussions_by_author_before_date) + (get_discussions_by_cashout_time) + (get_discussions_in_category_by_cashout_time) + // Witnesses (get_witnesses) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 0a8653a0a5..565009bd6b 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1356,7 +1356,6 @@ void database::cashout_comment_helper( const comment_object& cur, const comment_ adjust_total_payout( cur, sbd_created + to_sbd( vesting_steem_reward ) ); /// push virtual operation for this reward payout - //ilog( "Paying ${a}.${p} ${s} ${v}", ("a",cur.author)("p",cur.permlink)("s",sbd_reward)("v",vesting_steem_reward) ); push_applied_operation( comment_reward_operation( cur.author, cur.permlink, origin.author, origin.permlink, sbd_created, vest_created ) ); /// only recurse if the SBD created is more than $0.02, this should stop recursion quickly for @@ -1375,7 +1374,6 @@ void database::cashout_comment_helper( const comment_object& cur, const comment_ sbd_created = create_sbd( parent_author, parent_sbd_reward ); /// THE FOLLOWING IS NOT REQUIRED FOR VALIDATION - //ilog( "Paying ${a}.${p} ${s} ${v}", ("a",cur.parent_author)("p",cur.parent_permlink)("s",parent_sbd_reward)("v",parent_vesting_steem_reward) ); push_applied_operation( comment_reward_operation( cur.parent_author, cur.parent_permlink, origin.author, origin.permlink, sbd_created, vest_created ) ); adjust_total_payout( get_comment( cur.parent_author, cur.parent_permlink ), sbd_created + to_sbd( vesting_steem_reward ) ); } @@ -1385,7 +1383,6 @@ void database::cashout_comment_helper( const comment_object& cur, const comment_ /// THE FOLLOWING IS NOT REQUIRED FOR VALIDATION /// push virtual operation for this reward payout - //ilog( "Paying ${a}.${p} ${s} ${v}", ("a",cur.author)("p",cur.permlink)("s",sbd_reward)("v",vesting_steem_reward) ); push_applied_operation( comment_reward_operation( cur.author, cur.permlink, origin.author, origin.permlink, sbd_created, vest_created ) ); adjust_total_payout( cur, sbd_created + to_sbd( vesting_steem_reward ) ); } @@ -1432,8 +1429,6 @@ void database::process_comment_cashout() { if( head_block_time() < STEEMIT_FIRST_CASHOUT_TIME ) return; - wdump( (head_block_time())(head_block_num())(get_dynamic_global_properties().total_reward_shares2)(get_dynamic_global_properties().total_reward_fund_steem) ); - const auto& median_price = get_feed_history().current_median_history; const auto& cidx = get_index_type().indices().get(); @@ -1443,9 +1438,6 @@ void database::process_comment_cashout() { share_type unclaimed; const auto& cur = *current; ++current; bool paid = true; - try - { - //idump( (cur)(get_dynamic_global_properties().total_reward_shares2)(get_dynamic_global_properties().total_reward_fund_steem)(get_feed_history().current_median_history) ); asset sbd_created(0,SBD_SYMBOL); asset vest_created(0,VESTS_SYMBOL); @@ -1461,7 +1453,6 @@ void database::process_comment_cashout() { auto to_vesting = reward_tokens - to_sbd; unclaimed = pay_curators( cur, curator_rewards ); - //idump( (to_sbd)(to_vesting)(unclaimed) ); cashout_comment_helper( cur, cur, asset( to_vesting, STEEM_SYMBOL ), asset( to_sbd, STEEM_SYMBOL ) ); modify( cat, [&]( category_object& c ) { @@ -1499,12 +1490,7 @@ void database::process_comment_cashout() { ++vote_itr; remove(cur_vote); } - - if( !paid ) idump( (cur) ); - validate_invariants(); - } FC_CAPTURE_LOG_AND_RETHROW( (cur)(unclaimed) ); } - wdump( (get_dynamic_global_properties().total_reward_shares2)(get_dynamic_global_properties().total_reward_fund_steem) ); } /** From 5e280040325d454609c63eafa66a18ae99c83506 Mon Sep 17 00:00:00 2001 From: Reverse Flash Date: Tue, 10 May 2016 18:26:08 -0400 Subject: [PATCH 10/20] adding network_node_api to wildcard access --- libraries/app/application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 140e7c3625..ac01667052 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -331,6 +331,7 @@ namespace detail { wild_access.password_salt_b64 = "*"; wild_access.allowed_apis.push_back( "database_api" ); wild_access.allowed_apis.push_back( "network_broadcast_api" ); + wild_access.allowed_apis.push_back( "network_node_api" ); wild_access.allowed_apis.push_back( "history_api" ); wild_access.allowed_apis.push_back( "crypto_api" ); wild_access.allowed_apis.push_back( "private_message_api" ); From ae3d2e5282c82683b3641d79a01acfe3c09f30f9 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Wed, 11 May 2016 10:53:06 -0400 Subject: [PATCH 11/20] Fix virtual supply invariant failure. --- libraries/chain/database.cpp | 9 ++- python_scripts/tests/test_payouts.py | 110 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 python_scripts/tests/test_payouts.py diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 565009bd6b..c5f4f44b60 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1437,6 +1437,7 @@ void database::process_comment_cashout() { while( current != cidx.end() && current->cashout_time <= head_block_time() ) { share_type unclaimed; const auto& cur = *current; ++current; + try{ bool paid = true; asset sbd_created(0,SBD_SYMBOL); asset vest_created(0,VESTS_SYMBOL); @@ -1490,6 +1491,8 @@ void database::process_comment_cashout() { ++vote_itr; remove(cur_vote); } + validate_invariants(); + } FC_CAPTURE_LOG_AND_RETHROW( (cur) ); } } @@ -2517,7 +2520,7 @@ void database::adjust_supply( const asset& delta, bool adjust_vesting ) { } case SBD_SYMBOL: props.current_sbd_supply += delta; - props.virtual_supply += delta * get_feed_history().current_median_history; + props.virtual_supply = props.current_sbd_supply * get_feed_history().current_median_history + props.current_supply; assert( props.current_sbd_supply.amount.value >= 0 ); break; default: @@ -2741,9 +2744,9 @@ void database::validate_invariants()const FC_ASSERT( total_rshares2 == total_children_rshares2, "", ("total_rshares2", total_rshares2)("total_children_rshares2",total_children_rshares2)); FC_ASSERT( gpo.virtual_supply >= gpo.current_supply ); - /*if ( !get_feed_history().current_median_history.is_null() ) + if ( !get_feed_history().current_median_history.is_null() ) FC_ASSERT( gpo.current_sbd_supply * get_feed_history().current_median_history + gpo.current_supply - == gpo.virtual_supply, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("get_feed_history().current_median_history",get_feed_history().current_median_history)("gpo.current_supply",gpo.current_supply)("gpo.virtual_supply",gpo.virtual_supply) );*/ + == gpo.virtual_supply, "", ("gpo.current_sbd_supply",gpo.current_sbd_supply)("get_feed_history().current_median_history",get_feed_history().current_median_history)("gpo.current_supply",gpo.current_supply)("gpo.virtual_supply",gpo.virtual_supply) ); } FC_CAPTURE_LOG_AND_RETHROW( (head_block_num()) ); } diff --git a/python_scripts/tests/test_payouts.py b/python_scripts/tests/test_payouts.py new file mode 100644 index 0000000000..e88c1f8081 --- /dev/null +++ b/python_scripts/tests/test_payouts.py @@ -0,0 +1,110 @@ +""" +This test module will only run on a POSIX system. Windows support *may* be added at some point in the future. +""" +# Global imports +import json, operator, os, signal, sys + +from argparse import ArgumentParser +from pathlib import Path +from time import sleep + +# local imports +from steemdebugnode import DebugNode +from steemapi.steemnoderpc import SteemNodeRPC + +WAITING = True + +def main( ): + global WAITING + if( os.name != "posix" ): + print( "This script only works on POSIX systems" ) + return + + parser = ArgumentParser( description='Run a steemd debug node on an existing chain, trigger a hardfork' \ + ' and verify hardfork does not break invariants or block production' ) + parser.add_argument( '--steemd', '-s', type=str, required=True, help='The location of a steemd binary to run the debug node' ) + parser.add_argument( '--data-dir', '-d', type=str, required=True, help='The location of an existing data directory. ' + \ + 'The debug node will pull blocks from this directory when replaying the chain. The directory ' + \ + 'will not be changed.' ) + parser.add_argument( '--pause-node', '-p', type=bool, required=False, default=True, \ + help='True if the debug node should pause after it\'s tests. Default: false' ) + + args = parser.parse_args() + + steemd = Path( args.steemd ) + if( not steemd.exists() ): + print( 'Error: steemd does not exist.' ) + return + + steemd = steemd.resolve() + if( not steemd.is_file() ): + print( 'Error: steemd is not a file.' ) + return + + data_dir = Path( args.data_dir ) + if( not data_dir.exists() ): + print( 'Error: data_dir does not exist or is not a properly constructed steemd data directory' ) + + data_dir = data_dir.resolve() + if( not data_dir.is_dir() ): + print( 'Error: data_dir is not a directory' ) + + signal.signal( signal.SIGINT, sigint_handler ) + + debug_node = DebugNode( str( steemd ), str( data_dir ) ) + + with debug_node : + + run_steemd_tests( debug_node ) + + # Term on completion? + if( args.pause_node ): + print( "Letting the node hang for manual inspection..." ) + else: + WAITING = False + + while( WAITING ): + sleep( 1 ) + + +def run_steemd_tests( debug_node ): + from steemapi.steemnoderpc import SteemNodeRPC + + try: + print( 'Replaying blocks...', ) + sys.stdout.flush() + total_blocks = 0 + while( total_blocks % 100000 == 0 ): + total_blocks += debug_node.debug_push_blocks( 100000, skip_validate_invariants=True ) + print( 'Blocks Replayed: ' + str( total_blocks ) ) + sys.stdout.flush() + + print( "Triggering payouts" ) + sys.stdout.flush() + debug_node.debug_generate_blocks_until( 1467590400 ) + + print( "Generating blocks to verify nothing broke" ) + assert( debug_node.debug_generate_blocks( 10 ) == 10 ) + + print( "Done!" ) + print( "Getting comment dump:" ) + sys.stdout.flush() + rpc = SteemNodeRPC( 'ws://127.0.0.1:8095', '', '' ) + ret = rpc.get_discussions_by_cashout_time( '', '', str( 0xFFFFFFFF ) ); + + print( 'author, url, total_payout_value, abs_rshares, num_active_votes' ) + + for comment in ret: + print( comment[ 'author' ] + ', ' + comment[ 'url' ] + ', ' + comment[ 'total_payout_value' ] + ', ' + comment[ 'cashout_time' ] ) + + except ValueError as val_err: + print( str( val_err ) ) + + +def sigint_handler( signum, frame ): + global WAITING + WAITING = False + sleep( 3 ) + sys.exit( 0 ) + +main() \ No newline at end of file From 4426b7b02589eb26a5c8dfd219a0d215ee921730 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Thu, 12 May 2016 11:35:48 -0400 Subject: [PATCH 12/20] Update comment_vote_object to track extra information about votes. #22 --- libraries/chain/include/steemit/chain/comment_object.hpp | 6 ++++-- libraries/chain/steem_evaluator.cpp | 5 +++-- tests/tests/operation_tests.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index d50ef594fb..0a9000c6a1 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -115,8 +115,10 @@ namespace steemit { namespace chain { static const uint8_t type_id = impl_comment_vote_object_type; account_id_type voter; comment_id_type comment; - uint64_t weight = 0; ///< defines the score this vote receives, used by vote payout calc. 0 if a negative vote. + uint64_t weight = 0; ///< defines the score this vote receives, used by vote payout calc. 0 if a negative vote or changed votes. int64_t rshares = 0; ///< The number of rshares this vote is responsible for + uint16_t vote_percent = 0; ///< The percent weight of the vote + time_point_sec last_update; ///< The time of the last update of the vote }; struct by_comment_voter; @@ -338,6 +340,6 @@ FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), (net_rshares)(abs_rshares)(cashout_time)(total_vote_weight)(total_payout_value) ) FC_REFLECT_DERIVED( steemit::chain::comment_vote_object, (graphene::db::object), - (voter)(comment)(weight)(rshares) ) + (voter)(comment)(weight)(rshares)(vote_percent)(last_update) ) FC_REFLECT_DERIVED( steemit::chain::category_object, (graphene::db::object), (name)(abs_rshares)(total_payouts)(discussions)(last_update) ); diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 1eb7e45fb2..b4ea715f3a 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -593,6 +593,8 @@ void vote_evaluator::do_apply( const vote_operation& o ) { cv.voter = voter.id; cv.comment = comment.id; cv.rshares = rshares; + cv.vote_percent = o.weight; + cv.last_update = db().head_block_time(); if( rshares > 0 ) { u256 rshare256(rshares); u256 total256( comment.abs_rshares.value ); @@ -609,13 +611,12 @@ void vote_evaluator::do_apply( const vote_operation& o ) { else { FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_3 ), "Cannot undo votes until hardfork 3" ); - FC_ASSERT( o.weight == 0, "vote can only be removed, not modifed" ); db().modify( comment, [&]( comment_object& c ) { c.total_vote_weight -= itr->weight; c.net_rshares -= itr->rshares; - c.abs_rshares -= ( itr->rshares > 0 ? itr->rshares : -itr->rshares ); + c.total_vote_weight -= itr->weight; }); db().modify( *itr, [&]( comment_vote_object& cv ) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index aeb04c4925..1da5e584e1 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -857,7 +857,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( new_bob_comment.cashout_time == old_cashout_time ); BOOST_REQUIRE( sam_bob_vote->weight == 0 ); BOOST_REQUIRE( sam_bob_vote->rshares == 0 ); - BOOST_REQUIRE( db.get_account( "sam" ).voting_power == sam_voting_power ); + BOOST_REQUIRE( db.get_account( "sam" ).voting_power == sam_vote_power ); validate_database(); } From e66fbc0a6483d884fb5e12f55079fb58ca5b1ddc Mon Sep 17 00:00:00 2001 From: Reverse Flash Date: Thu, 12 May 2016 12:03:46 -0400 Subject: [PATCH 13/20] update index and permlink format --- libraries/app/database_api.cpp | 110 ++++++------ libraries/app/include/steemit/app/state.hpp | 4 +- libraries/chain/database.cpp | 3 +- .../include/steemit/chain/comment_object.hpp | 158 +++++++----------- .../chain/include/steemit/chain/database.hpp | 2 +- libraries/chain/steem_evaluator.cpp | 35 +++- 6 files changed, 152 insertions(+), 160 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 3ef9b280c2..3378266ef3 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -786,7 +786,7 @@ void database_api::set_url( discussion& d )const { } vector database_api::get_content_replies( string author, string permlink )const { - const auto& by_permlink_idx = my->_db.get_index_type< comment_index >().indices().get< by_parent_total_pending_payout >(); + const auto& by_permlink_idx = my->_db.get_index_type< comment_index >().indices().get< by_total_pending_payout_in_category >(); auto itr = by_permlink_idx.find( boost::make_tuple( author, permlink ) ); vector result; while( itr != by_permlink_idx.end() && itr->parent_author == author && itr->parent_permlink == permlink ) @@ -825,16 +825,20 @@ vector database_api::get_discussions_by_last_update( string start_pa return result; } -vector database_api::get_discussions_by_created( string start_auth, string start_permlink, uint32_t limit )const { - const auto& last_update_idx = my->_db.get_index_type< comment_index >().indices().get< by_created >(); +vector database_api::get_discussions_in_category_by_last_update( string category, string start_auth, string start_permlink, uint32_t limit )const { + const auto& last_update_in_category = my->_db.get_index_type< comment_index >().indices().get< by_last_update_in_category >(); - auto itr = last_update_idx.begin(); + auto itr = last_update_in_category.lower_bound( boost::make_tuple( "", category, fc::time_point_sec::maximum() ) ); if( start_auth.size() ) - itr = last_update_idx.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + itr = last_update_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); vector result; - while( itr != last_update_idx.end() && result.size() < limit && !itr->parent_author.size() ) { + while( itr != last_update_in_category.end() && + itr->parent_permlink == category && + !itr->parent_author.size() + && result.size() < limit ) + { result.push_back( *itr ); set_pending_payout(result.back()); result.back().active_votes = get_active_votes( itr->author, itr->permlink ); @@ -843,17 +847,16 @@ vector database_api::get_discussions_by_created( string start_auth, return result; } -vector database_api::get_discussions_by_cashout_time( string start_auth, string start_permlink, uint32_t limit )const { - const auto& cashout_time_idx = my->_db.get_index_type< comment_index >().indices().get< by_cashout_time >(); +vector database_api::get_discussions_by_created( string start_auth, string start_permlink, uint32_t limit )const { + const auto& last_update_idx = my->_db.get_index_type< comment_index >().indices().get< by_last_update >(); - auto itr = cashout_time_idx.begin(); + auto itr = last_update_idx.begin(); if( start_auth.size() ) - itr = cashout_time_idx.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + itr = last_update_idx.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); vector result; - while( itr != cashout_time_idx.end() && result.size() < limit ) { - idump((*itr)); + while( itr != last_update_idx.end() && result.size() < limit && !itr->parent_author.size() ) { result.push_back( *itr ); set_pending_payout(result.back()); result.back().active_votes = get_active_votes( itr->author, itr->permlink ); @@ -861,18 +864,20 @@ vector database_api::get_discussions_by_cashout_time( string start_a } return result; } -vector database_api::get_discussions_in_category_by_cashout_time( string category, string start_auth, string start_permlink, uint32_t limit )const { - vector result; - const auto& cashout_time_in_category = my->_db.get_index_type< comment_index >().indices().get< by_cashout_time_in_category >(); - auto itr = cashout_time_in_category.lower_bound( boost::make_tuple( category, fc::time_point_sec::maximum() ) ); +vector database_api::get_discussions_in_category_by_created( string category, string start_auth, string start_permlink, uint32_t limit )const { + const auto& last_update_in_category = my->_db.get_index_type< comment_index >().indices().get< by_last_update_in_category >(); + + auto itr = last_update_in_category.lower_bound( boost::make_tuple( "", category, fc::time_point_sec::maximum() ) ); if( start_auth.size() ) - itr = cashout_time_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + itr = last_update_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); - while( itr != cashout_time_in_category.end() && + vector result; + while( itr != last_update_in_category.end() && itr->parent_permlink == category && - result.size() < limit ) + !itr->parent_author.size() + && result.size() < limit ) { result.push_back( *itr ); set_pending_payout(result.back()); @@ -882,20 +887,19 @@ vector database_api::get_discussions_in_category_by_cashout_time( st return result; } -vector database_api::get_discussions_in_category_by_last_update( string category, string start_auth, string start_permlink, uint32_t limit )const { - const auto& last_update_in_category = my->_db.get_index_type< comment_index >().indices().get< by_last_update_in_category >(); - auto itr = last_update_in_category.lower_bound( boost::make_tuple( "", category, fc::time_point_sec::maximum() ) ); + +vector database_api::get_discussions_by_cashout_time( string start_auth, string start_permlink, uint32_t limit )const { + const auto& cashout_time_idx = my->_db.get_index_type< comment_index >().indices().get< by_cashout_time >(); + + auto itr = cashout_time_idx.begin(); if( start_auth.size() ) - itr = last_update_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + itr = cashout_time_idx.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); vector result; - while( itr != last_update_in_category.end() && - itr->parent_permlink == category && - !itr->parent_author.size() - && result.size() < limit ) - { + while( itr != cashout_time_idx.end() && result.size() < limit ) { + idump((*itr)); result.push_back( *itr ); set_pending_payout(result.back()); result.back().active_votes = get_active_votes( itr->author, itr->permlink ); @@ -903,20 +907,18 @@ vector database_api::get_discussions_in_category_by_last_update( str } return result; } +vector database_api::get_discussions_in_category_by_cashout_time( string category, string start_auth, string start_permlink, uint32_t limit )const { + vector result; + const auto& cashout_time_in_category = my->_db.get_index_type< comment_index >().indices().get< by_cashout_time_in_category >(); -vector database_api::get_discussions_in_category_by_created( string category, string start_auth, string start_permlink, uint32_t limit )const { - const auto& last_update_in_category = my->_db.get_index_type< comment_index >().indices().get< by_created_in_category >(); - - auto itr = last_update_in_category.lower_bound( boost::make_tuple( "", category, fc::time_point_sec::maximum() ) ); + auto itr = cashout_time_in_category.lower_bound( boost::make_tuple( category, fc::time_point_sec::maximum() ) ); if( start_auth.size() ) - itr = last_update_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + itr = cashout_time_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); - vector result; - while( itr != last_update_in_category.end() && + while( itr != cashout_time_in_category.end() && itr->parent_permlink == category && - !itr->parent_author.size() - && result.size() < limit ) + result.size() < limit ) { result.push_back( *itr ); set_pending_payout(result.back()); @@ -926,6 +928,8 @@ vector database_api::get_discussions_in_category_by_created( string return result; } + + vector database_api::get_discussions_by_total_pending_payout( string start_auth, string start_permlink, uint32_t limit )const { const auto& total_pending_payout_idx = my->_db.get_index_type< comment_index >().indices().get< by_total_pending_payout >(); @@ -1072,7 +1076,7 @@ vector database_api::get_discussions_by_author_before_date( FC_ASSERT( limit <= 100 ); int count = 0; - const auto& didx = my->_db.get_index_type().indices().get(); + const auto& didx = my->_db.get_index_type().indices().get(); if( before_date == time_point_sec() ) before_date = time_point_sec::maximum(); @@ -1099,16 +1103,17 @@ vector database_api::get_discussions_by_author_before_date( state database_api::get_state( string path )const { + state _state; + _state.props = get_dynamic_global_properties(); + _state.current_route = path; + + try { if( path.size() && path[0] == '/' ) path = path.substr(1); /// remove '/' from front if( !path.size() ) path = "trending"; - state _state; - _state.props = get_dynamic_global_properties(); - _state.current_route = path; - /// FETCH CATEGORY STATE auto trending_cat = get_trending_categories( "", 100 ); for( const auto& c : trending_cat ) @@ -1194,7 +1199,7 @@ state database_api::get_state( string path )const } } else if( part[1] == "posts" ) { int count = 0; - const auto& pidx = my->_db.get_index_type().indices().get(); + const auto& pidx = my->_db.get_index_type().indices().get(); auto itr = pidx.lower_bound( boost::make_tuple(acnt, time_point_sec::maximum() ) ); eacnt.posts = vector(); while( itr != pidx.end() && itr->author == acnt && count < 100 ) { @@ -1204,19 +1209,6 @@ state database_api::get_state( string path )const ++count; } } else if( part[1].size() == 0 || part[1] == "blog" ) { - if( part[2].size() ) { - int count = 0; - const auto& pidx = my->_db.get_index_type().indices().get(); - auto itr = pidx.lower_bound( boost::make_tuple(acnt, std::string(""), part[2], time_point_sec::maximum() ) ); - while( itr != pidx.end() && itr->author == acnt && count < 100 && !itr->parent_author.size() ) { - eacnt.blog_category[part[2]].push_back(itr->permlink); - _state.content[acnt+"/"+itr->permlink] = *itr; - set_pending_payout( _state.content[acnt+"/"+itr->permlink] ); - ++itr; - ++count; - } - } - else { int count = 0; const auto& pidx = my->_db.get_index_type().indices().get(); auto itr = pidx.lower_bound( boost::make_tuple(acnt, std::string(""), time_point_sec::maximum() ) ); @@ -1228,7 +1220,6 @@ state database_api::get_state( string path )const ++itr; ++count; } - } } } /// pull a complete discussion @@ -1324,7 +1315,10 @@ state database_api::get_state( string path )const _state.witness_schedule = my->_db.get_witness_schedule_object(); - return _state; + } catch ( const fc::exception& e ) { + _state.error = e.to_detail_string(); + } + return _state; } annotated_signed_transaction database_api::get_transaction( transaction_id_type id )const { diff --git a/libraries/app/include/steemit/app/state.hpp b/libraries/app/include/steemit/app/state.hpp index c22f6e2dde..0a5686fa00 100644 --- a/libraries/app/include/steemit/app/state.hpp +++ b/libraries/app/include/steemit/app/state.hpp @@ -132,6 +132,7 @@ namespace steemit { namespace app { vector pow_queue; map witnesses; witness_schedule_object witness_schedule; + string error; }; } } @@ -147,5 +148,6 @@ FC_REFLECT( steemit::app::account_vote, (authorperm)(weight) ); FC_REFLECT( steemit::app::discussion_index, (category)(trending)(recent)(active)(maturing)(best) ) FC_REFLECT( steemit::app::category_index, (trending)(active)(recent)(best) ) -FC_REFLECT( steemit::app::state, (current_route)(props)(category_idx)(categories)(content)(accounts)(pow_queue)(witnesses)(discussion_idx)(witness_schedule) ) FC_REFLECT_DERIVED( steemit::app::discussion, (steemit::chain::comment_object), (url)(root_title)(pending_payout_value)(total_pending_payout_value)(active_votes)(replies) ) + +FC_REFLECT( steemit::app::state, (current_route)(props)(category_idx)(categories)(content)(accounts)(pow_queue)(witnesses)(discussion_idx)(witness_schedule)(error) ) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 46145aa887..e295491807 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1262,6 +1262,7 @@ void database::adjust_rshares2( const comment_object& c, fc::uint128_t old_rshar modify( c, [&](comment_object& comment ){ comment.children_rshares2 -= old_rshares2; comment.children_rshares2 += new_rshares2; + comment.active = head_block_time(); }); if( c.depth ) { adjust_rshares2( get_comment( c.parent_author, c.parent_permlink ), old_rshares2, new_rshares2 ); @@ -2631,7 +2632,7 @@ void database::process_hardforks() } FC_CAPTURE_AND_RETHROW() } -bool database::has_hardfork( uint32_t hardfork ) +bool database::has_hardfork( uint32_t hardfork )const { return hardfork_property_id_type()( *this ).processed_hardforks.size() > hardfork; } diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index 1084c91ab4..e9cfca494f 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -80,6 +80,7 @@ namespace steemit { namespace chain { string json_metadata = ""; time_point_sec last_update; time_point_sec created; + time_point_sec active; ///< the last time this post was "touched" by voting or reply uint8_t depth = 0; ///< used to track max nested depth uint32_t children = 0; ///< used to track the total number of children, grandchildren, etc... @@ -198,35 +199,21 @@ namespace steemit { namespace chain { - - struct by_permlink; + struct by_cashout_time; /// cashout_time + struct by_permlink; /// author, perm + struct by_active; /// parent_auth, active + struct by_active_in_category; /// parent_auth, parent_perm, active + struct by_cashout_time_in_category; /// parent_auth, cashout_time struct by_pending_payout; - struct by_payout; - struct by_created; - struct by_created_in_category; - struct by_parent_pending_payout; - struct by_parent_total_pending_payout; - struct by_parent_payout; - struct by_parent_date; - struct by_author_pending_payout; - struct by_author_payout; - struct by_author_date; - struct by_parent; - struct by_parent_created; - struct by_cashout; - struct by_parent_cashout; - struct by_pending_payout; /// rshares - struct by_parent_pending_payout; - struct by_payout; /// rshares - struct by_parent_payout; + struct by_pending_payout_in_category; struct by_total_pending_payout; struct by_total_pending_payout_in_category; - struct by_last_update; - struct by_last_update_in_category; - struct by_cashout_time; - 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 + struct by_last_update; /// parent_auth, last_update + struct by_last_update_in_category; /// parent_auth, parent_perm, last_update + struct by_payout; /// parent_auth, last_update + struct by_payout_in_category; /// parent_auth, parent_perm, last_update + struct by_blog; + struct by_author_last_update; /** * @ingroup object_index @@ -234,6 +221,7 @@ namespace steemit { namespace chain { typedef multi_index_container< comment_object, indexed_by< + /// CONSENUSS INDICIES - used by evaluators ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >, ordered_unique< tag< by_cashout_time >, composite_key< comment_object, @@ -241,63 +229,44 @@ namespace steemit { namespace chain { member< object, object_id_type, &object::id > > >, - ordered_unique< tag< by_cashout_time_in_category >, - composite_key< comment_object, - member< comment_object, string, &comment_object::category >, - member< comment_object, time_point_sec, &comment_object::cashout_time >, - member< object, object_id_type, &object::id > - >, - composite_key_compare< std::less< string >, std::less, std::less > - >, - ordered_unique< tag< by_permlink >, + ordered_unique< tag< by_permlink >, /// used by consensus to find posts referenced in ops composite_key< comment_object, member< comment_object, string, &comment_object::author >, member< comment_object, string, &comment_object::permlink > >, composite_key_compare< std::less< string >, std::less< string > > - >, - ordered_unique< tag< by_parent >, + > + +//#ifndef IS_LOW_MEM + , + ordered_unique< tag, composite_key< comment_object, - member< comment_object, string, &comment_object::parent_author >, - member< comment_object, string, &comment_object::parent_permlink >, + member< comment_object, string, &comment_object::parent_author >, /// parent author of "" is root topic + member< comment_object, time_point_sec, &comment_object::active >, member< object, object_id_type, &object::id > - > - >, - ordered_unique< tag< by_blog >, - composite_key< comment_object, - member< comment_object, string, &comment_object::author >, - member< comment_object, string, &comment_object::parent_author >, - member< comment_object, time_point_sec, &comment_object::created >, - member< comment_object, string, &comment_object::permlink > >, - composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > - >, - ordered_unique< tag< by_blog_category >, - composite_key< comment_object, - member< comment_object, string, &comment_object::author >, - member< comment_object, string, &comment_object::parent_author >, - member< comment_object, string, &comment_object::parent_permlink >, - member< comment_object, time_point_sec, &comment_object::created >, - member< comment_object, string, &comment_object::permlink > - >, - composite_key_compare< std::less< string >, std::less< string >, std::less< string >, std::greater, std::less > + composite_key_compare< std::less, std::greater, std::less > >, - ordered_unique< tag< by_parent_created >, + /// ACTIVE INDEX - used to find posts that have recently been touched by votes, edits or replies + ordered_unique< tag< by_active_in_category >, /// AKA - by_parent sorted by active composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, member< comment_object, string, &comment_object::parent_permlink >, - member< comment_object, time_point_sec, &comment_object::created >, + member< comment_object, time_point_sec, &comment_object::active >, member< object, object_id_type, &object::id > >, composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > >, - ordered_unique< tag< by_created >, + /// CASHOUT INDICIDES (NOT IN CONSENSUS) + ordered_unique< tag< by_cashout_time_in_category >, composite_key< comment_object, - member< comment_object, time_point_sec, &comment_object::created >, + member< comment_object, string, &comment_object::category >, + member< comment_object, time_point_sec, &comment_object::cashout_time >, member< object, object_id_type, &object::id > >, - composite_key_compare< std::greater, std::less > + composite_key_compare< std::less< string >, std::less, std::less > >, + /// PENDING PAYOUT relative to a parent ordered_unique< tag< by_pending_payout >, composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, @@ -306,21 +275,23 @@ namespace steemit { namespace chain { >, composite_key_compare< std::less, std::greater, std::less > >, - ordered_unique< tag< by_total_pending_payout >, + ordered_unique< tag< by_pending_payout_in_category >, composite_key< comment_object, - member< comment_object, string, &comment_object::parent_author >, /// parent author of "" is root topic - member< comment_object, fc::uint128_t, &comment_object::children_rshares2 >, + member< comment_object, string, &comment_object::parent_author >, + member< comment_object, string, &comment_object::parent_permlink >, + member< comment_object, share_type, &comment_object::net_rshares >, member< object, object_id_type, &object::id > >, - composite_key_compare< std::less, std::greater, std::less > + composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > >, - ordered_unique< tag, + /// TOTAL PENDING PAYOUT - this is the default TRENDING ORDER + ordered_unique< tag< by_total_pending_payout >, composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, /// parent author of "" is root topic - member< comment_object, time_point_sec, &comment_object::last_update >, + member< comment_object, fc::uint128_t, &comment_object::children_rshares2 >, member< object, object_id_type, &object::id > >, - composite_key_compare< std::less, std::greater, std::less > + composite_key_compare< std::less, std::greater, std::less > >, ordered_unique< tag< by_total_pending_payout_in_category >, composite_key< comment_object, @@ -331,42 +302,25 @@ namespace steemit { namespace chain { >, composite_key_compare< std::less, std::less, std::greater, std::less > >, - ordered_unique< tag< by_last_update_in_category >, + /// used to sort all posts by the last time they were edited + ordered_unique< tag, composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, /// parent author of "" is root topic - member< comment_object, string, &comment_object::parent_permlink >, /// permlink is the category member< comment_object, time_point_sec, &comment_object::last_update >, member< object, object_id_type, &object::id > >, - composite_key_compare< std::less, std::less, std::greater, std::less > + composite_key_compare< std::less, std::greater, std::less > >, - ordered_unique< tag< by_created_in_category >, + ordered_unique< tag< by_last_update_in_category >, composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, /// parent author of "" is root topic member< comment_object, string, &comment_object::parent_permlink >, /// permlink is the category - member< comment_object, time_point_sec, &comment_object::created >, + member< comment_object, time_point_sec, &comment_object::last_update >, member< object, object_id_type, &object::id > >, composite_key_compare< std::less, std::less, std::greater, std::less > >, - ordered_unique< tag< by_parent_pending_payout >, - composite_key< comment_object, - member< comment_object, string, &comment_object::parent_author >, - member< comment_object, string, &comment_object::parent_permlink >, - member< comment_object, share_type, &comment_object::net_rshares >, - member< object, object_id_type, &object::id > - >, - composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > - >, - ordered_unique< tag< by_parent_total_pending_payout >, - composite_key< comment_object, - member< comment_object, string, &comment_object::parent_author >, - member< comment_object, string, &comment_object::parent_permlink >, - member< comment_object, fc::uint128, &comment_object::children_rshares2 >, - member< object, object_id_type, &object::id > - >, - composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > - >, + /// posts with the high dollar value received ordered_unique< tag< by_payout >, composite_key< comment_object, member< comment_object, asset, &comment_object::total_payout_value >, @@ -374,7 +328,7 @@ namespace steemit { namespace chain { >, composite_key_compare< std::greater, std::less > >, - ordered_unique< tag< by_parent_payout >, + ordered_unique< tag< by_payout_in_category >, composite_key< comment_object, member< comment_object, string, &comment_object::parent_author >, member< comment_object, string, &comment_object::parent_permlink >, @@ -383,14 +337,26 @@ namespace steemit { namespace chain { >, composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > >, - ordered_unique< tag< by_author_date >, + /// used to find all top-level posts (blog posts) + ordered_unique< tag< by_blog >, composite_key< comment_object, member< comment_object, string, &comment_object::author >, + member< comment_object, string, &comment_object::parent_author >, member< comment_object, time_point_sec, &comment_object::created >, + member< comment_object, string, &comment_object::permlink > + >, + composite_key_compare< std::less< string >, std::less< string >, std::greater, std::less > + >, + /// used to find all posts by an author + ordered_unique< tag< by_author_last_update >, + composite_key< comment_object, + member< comment_object, string, &comment_object::author >, + member< comment_object, time_point_sec, &comment_object::last_update >, member< object, object_id_type, &object::id > >, composite_key_compare< std::less< string >, std::greater, std::less > > +// #endif /// IS_LOW_MEM > > comment_multi_index_type; @@ -403,7 +369,7 @@ namespace steemit { namespace chain { FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), (author)(permlink) (category)(parent_author)(parent_permlink) - (title)(body)(json_metadata)(last_update)(created) + (title)(body)(json_metadata)(last_update)(created)(active) (depth)(children)(children_rshares2) (net_rshares)(abs_rshares)(cashout_time)(total_vote_weight)(total_payout_value)(stats) ) diff --git a/libraries/chain/include/steemit/chain/database.hpp b/libraries/chain/include/steemit/chain/database.hpp index 40c6242822..3bf15feace 100644 --- a/libraries/chain/include/steemit/chain/database.hpp +++ b/libraries/chain/include/steemit/chain/database.hpp @@ -334,7 +334,7 @@ namespace steemit { namespace chain { void perform_vesting_share_split( uint32_t magnitude ); void retally_witness_votes(); - bool has_hardfork( uint32_t hardfork ); + bool has_hardfork( uint32_t hardfork )const; /* For testing and debugging only. Given a hardfork with id N, applies all hardforks with id <= N */ diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 024bc16759..7f0119b0f6 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -12,10 +12,21 @@ namespace steemit { namespace chain { using fc::uint128_t; -void inline validate_permlink( string permlink ) +/** + * Allow GROUP / TOPIC + */ +void inline validate_permlink( string permlink, const database& db ) { + bool allow_slash = db.has_hardfork( STEEMIT_HARDFORK_0_5_0 ); + FC_ASSERT( permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH ); + int char_count = 0; + int slash_count = 0; + int after_slash = 0; + bool last_was_slash = false; + bool last_was_dash = false; + for( auto c : permlink ) { switch( c ) @@ -24,12 +35,26 @@ void inline validate_permlink( string permlink ) case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + ++char_count; + last_was_dash = false; + if( allow_slash ) FC_ASSERT( !last_was_dash ); + ++after_slash; + break; case '-': + if( allow_slash ) FC_ASSERT( char_count, "must have characters before -" ); + last_was_dash = true; + ++char_count; + break; + case '/': + FC_ASSERT( allow_slash && !slash_count && char_count ); + ++slash_count; + after_slash = 0; break; default: FC_ASSERT( !"Invalid permlink character:", "${s}", ("s", std::string() + c ) ); } } + if( allow_slash ) FC_ASSERT( after_slash, "there must be charcters after - or /" ); } void witness_update_evaluator::do_apply( const witness_update_operation& o ) @@ -152,8 +177,8 @@ void comment_evaluator::do_apply( const comment_operation& o ) { if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) { - validate_permlink( o.parent_permlink ); - validate_permlink( o.permlink ); + validate_permlink( o.parent_permlink, db() ); + validate_permlink( o.permlink, db() ); } if ( o.parent_author.size() == 0 ) @@ -175,6 +200,7 @@ void comment_evaluator::do_apply( const comment_operation& o ) com.last_update = db().head_block_time(); com.created = com.last_update; com.cashout_time = com.last_update + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS); + com.active = com.last_update; #ifndef IS_LOW_MEM com.title = o.title; @@ -211,9 +237,11 @@ void comment_evaluator::do_apply( const comment_operation& o ) /// this loop can be skiped for validate-only nodes as it is merely gathering stats for indicies #ifndef IS_LOW_MEM + auto now = db().head_block_time(); while( parent ) { db().modify( *parent, [&]( comment_object& p ){ p.children++; + p.active = now; }); if( parent->parent_author.size() ) parent = &db().get_comment( parent->parent_author, parent->parent_permlink ); @@ -241,6 +269,7 @@ void comment_evaluator::do_apply( const comment_operation& o ) } com.last_update = db().head_block_time(); + com.active = com.last_update; com.cashout_time = com.last_update + fc::seconds(STEEMIT_CASHOUT_WINDOW_SECONDS); From 910eab543fcca91eba144a76a6ba63e2a79fbb43 Mon Sep 17 00:00:00 2001 From: Reverse Flash Date: Thu, 12 May 2016 13:32:00 -0400 Subject: [PATCH 14/20] adding API to fetch active content --- libraries/app/database_api.cpp | 69 ++++++++++++++++++- .../app/include/steemit/app/database_api.hpp | 5 ++ libraries/app/include/steemit/app/state.hpp | 3 +- libraries/chain/database.cpp | 3 +- 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 0481df4839..f5dce7014a 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -127,7 +127,6 @@ void database_api::set_subscribe_callback( std::function c void database_api_impl::set_subscribe_callback( std::function cb, bool clear_filter ) { - edump((clear_filter)); _subscribe_callback = cb; if( clear_filter || !cb ) { @@ -847,6 +846,54 @@ vector database_api::get_discussions_in_category_by_last_update( str return result; } + +vector database_api::get_discussions_by_last_active( string start_parent_author, string start_permlink, uint32_t limit )const { + + idump((start_parent_author)(start_permlink)(limit) ); + const auto& last_activity_idx = my->_db.get_index_type< comment_index >().indices().get< by_active >(); + + auto itr = last_activity_idx.begin(); + + + if( start_permlink.size() ) + itr = last_activity_idx.iterator_to( my->_db.get_comment( start_parent_author, start_permlink ) ); + else if( start_parent_author.size() ) { + itr = last_activity_idx.lower_bound( boost::make_tuple( start_parent_author, time_point_sec::maximum(), object_id_type() ) ); + } + + vector result; + while( itr != last_activity_idx.end() && result.size() < limit ) { + result.push_back( *itr ); + set_pending_payout(result.back()); + result.back().active_votes = get_active_votes( itr->author, itr->permlink ); + ++itr; + } + return result; +} + +vector database_api::get_discussions_in_category_by_last_active( string category, string start_auth, string start_permlink, uint32_t limit )const { + const auto& last_activity_in_category = my->_db.get_index_type< comment_index >().indices().get< by_active_in_category >(); + + auto itr = last_activity_in_category.lower_bound( boost::make_tuple( "", category, fc::time_point_sec::maximum() ) ); + + if( start_auth.size() ) + itr = last_activity_in_category.iterator_to( my->_db.get_comment( start_auth, start_permlink ) ); + + vector result; + while( itr != last_activity_in_category.end() && + itr->parent_permlink == category && + !itr->parent_author.size() + && result.size() < limit ) + { + result.push_back( *itr ); + set_pending_payout(result.back()); + result.back().active_votes = get_active_votes( itr->author, itr->permlink ); + ++itr; + } + return result; +} + + vector database_api::get_discussions_by_created( string start_auth, string start_permlink, uint32_t limit )const { const auto& last_update_idx = my->_db.get_index_type< comment_index >().indices().get< by_last_update >(); @@ -1190,7 +1237,6 @@ state database_api::get_state( string path )const } } else if( part[1] == "recent-replies" ) { auto replies = get_discussions_by_last_update( acnt, "", 50 ); - edump((replies)); eacnt.recent_replies = vector(); for( const auto& reply : replies ) { auto reply_ref = reply.author+"/"+reply.permlink; @@ -1303,6 +1349,25 @@ state database_api::get_state( string path )const _state.content[key] = std::move(d); } } + else if( part[0] == "active" && part[1] == "") { + auto trending_disc = get_discussions_by_last_active( "", "", 20 ); + auto& didx = _state.discussion_idx[""]; + for( const auto& d : trending_disc ) { + auto key = d.author +"/" + d.permlink; + didx.active.push_back( key ); + accounts.insert(d.author); + _state.content[key] = std::move(d); + } + } else if( part[0] == "active" ) { + auto trending_disc = get_discussions_in_category_by_last_active( part[1], "", "", 20 ); + auto& didx = _state.discussion_idx[part[1]]; + for( const auto& d : trending_disc ) { + auto key = d.author +"/" + d.permlink; + didx.active.push_back( key ); + accounts.insert(d.author); + _state.content[key] = std::move(d); + } + } for( const auto& a : accounts ) { diff --git a/libraries/app/include/steemit/app/database_api.hpp b/libraries/app/include/steemit/app/database_api.hpp index 87f2c35605..7e4487cfff 100755 --- a/libraries/app/include/steemit/app/database_api.hpp +++ b/libraries/app/include/steemit/app/database_api.hpp @@ -303,6 +303,9 @@ class database_api vector get_discussions_by_last_update( string start_author, string start_permlink, uint32_t limit )const; vector get_discussions_in_category_by_last_update( string category, string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_by_last_active( string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_in_category_by_last_active( string category, string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_by_created( string start_author, string start_permlink, uint32_t limit )const; vector get_discussions_in_category_by_created( string category, string start_author, string start_permlink, uint32_t limit )const; @@ -400,8 +403,10 @@ FC_API(steemit::app::database_api, (get_discussions_by_total_pending_payout) (get_discussions_in_category_by_total_pending_payout) (get_discussions_by_last_update) + (get_discussions_by_last_active) (get_discussions_by_created) (get_discussions_in_category_by_last_update) + (get_discussions_in_category_by_last_active) (get_discussions_in_category_by_created) (get_discussions_by_author_before_date) (get_discussions_by_cashout_time) diff --git a/libraries/app/include/steemit/app/state.hpp b/libraries/app/include/steemit/app/state.hpp index 0a5686fa00..c32d0e82bd 100644 --- a/libraries/app/include/steemit/app/state.hpp +++ b/libraries/app/include/steemit/app/state.hpp @@ -13,6 +13,7 @@ namespace steemit { namespace app { vector trending; /// pending lifetime payout vector recent; /// creation date vector active; /// last update or reply + vector votes; /// last update or reply vector maturing; /// about to be paid out vector best; /// total lifetime payout }; @@ -146,7 +147,7 @@ FC_REFLECT_DERIVED( steemit::app::extended_account, FC_REFLECT( steemit::app::vote_state, (voter)(weight) ); FC_REFLECT( steemit::app::account_vote, (authorperm)(weight) ); -FC_REFLECT( steemit::app::discussion_index, (category)(trending)(recent)(active)(maturing)(best) ) +FC_REFLECT( steemit::app::discussion_index, (category)(trending)(recent)(active)(votes)(maturing)(best) ) FC_REFLECT( steemit::app::category_index, (trending)(active)(recent)(best) ) FC_REFLECT_DERIVED( steemit::app::discussion, (steemit::chain::comment_object), (url)(root_title)(pending_payout_value)(total_pending_payout_value)(active_votes)(replies) ) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 9023cf1e7b..717bc8c975 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1261,7 +1261,8 @@ void database::adjust_rshares2( const comment_object& c, fc::uint128_t old_rshar modify( c, [&](comment_object& comment ){ comment.children_rshares2 -= old_rshares2; comment.children_rshares2 += new_rshares2; - comment.active = head_block_time(); + if( new_rshares2 > old_rshares2 ) /// down't update active index for down votes + comment.active = head_block_time(); }); if( c.depth ) { adjust_rshares2( get_comment( c.parent_author, c.parent_permlink ), old_rshares2, new_rshares2 ); From 3ff564e01f2b079b63b1e06012cfae9f47338f68 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Thu, 12 May 2016 14:17:45 -0400 Subject: [PATCH 15/20] Fix build for unit tests. File was missing from merge. --- tests/tests/operation_tests.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index c798ec5b4c..2008ffa04d 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -818,8 +818,8 @@ BOOST_AUTO_TEST_CASE( vote_apply ) validate_database(); - BOOST_TEST_MESSAGE( "--- Testing removing votes for hardfork 3" ); - db.set_hardfork( STEEMIT_HARDFORK_3 ); + /* + BOOST_TEST_MESSAGE( "--- Testing removing votes for hardfork 0_5_0" ); BOOST_TEST_MESSAGE( "--- Test failure when modifying a vote to a non-zero weight" ); @@ -887,7 +887,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( sam_bob_vote->rshares == 0 ); BOOST_REQUIRE( db.get_account( "sam" ).voting_power == sam_vote_power ); - validate_database(); + validate_database();*/ } } FC_LOG_AND_RETHROW() From 1753147bf0cea028a8aad7b9e86da8b0697967b2 Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Thu, 12 May 2016 16:09:55 -0400 Subject: [PATCH 16/20] First implementation and initial testing. #22 --- .../chain/include/steemit/chain/config.hpp | 2 + libraries/chain/steem_evaluator.cpp | 47 ++++++++++- tests/tests/operation_tests.cpp | 78 ++++++++----------- 3 files changed, 80 insertions(+), 47 deletions(-) diff --git a/libraries/chain/include/steemit/chain/config.hpp b/libraries/chain/include/steemit/chain/config.hpp index 4da3f4a723..0f83ded0bd 100644 --- a/libraries/chain/include/steemit/chain/config.hpp +++ b/libraries/chain/include/steemit/chain/config.hpp @@ -20,6 +20,7 @@ #define STEEMIT_MINING_TIME (fc::time_point_sec(1451606400)) #define STEEMIT_FIRST_CASHOUT_TIME (fc::time_point_sec(1451606400)) #define STEEMIT_CASHOUT_WINDOW_SECONDS (60*60) /// 1 hr +#define STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD (60*10) /// 10 minutes #define STEEMIT_ORIGINAL_MIN_ACCOUNT_CREATION_FEE 0 #define STEEMIT_MIN_ACCOUNT_CREATION_FEE 0 @@ -40,6 +41,7 @@ #define STEEMIT_MINING_TIME (fc::time_point_sec(1458838800)) #define STEEMIT_FIRST_CASHOUT_TIME (fc::time_point_sec(1467590400)) /// July 4th #define STEEMIT_CASHOUT_WINDOW_SECONDS (60*60*24) /// 1 day +#define STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD (60*60*2) /// 2 hours #define STEEMIT_ORIGINAL_MIN_ACCOUNT_CREATION_FEE 100000 #define STEEMIT_MIN_ACCOUNT_CREATION_FEE 1 diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index b4ea715f3a..9f03109477 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -610,20 +610,61 @@ void vote_evaluator::do_apply( const vote_operation& o ) { } else { - FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_3 ), "Cannot undo votes until hardfork 3" ); + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_3 ), "Cannot undo votes until hardfork 0_5_0" ); + + auto elapsed_seconds = (db().head_block_time() - voter.last_vote_time).to_seconds(); + auto regenerated_power = ((STEEMIT_100_PERCENT - voter.voting_power) * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS; + auto current_power = std::min( int64_t(voter.voting_power + regenerated_power), int64_t(STEEMIT_100_PERCENT) ); + FC_ASSERT( current_power > 0 ); + + int64_t abs_weight = abs(o.weight); + auto used_power = (current_power * abs_weight) / STEEMIT_100_PERCENT; + used_power /= 20; /// a 100% vote means use 5% of voting power which should force users to spread their votes around over 20+ posts + + int64_t abs_rshares = ((uint128_t(voter.vesting_shares.amount.value) * used_power) / STEEMIT_100_PERCENT).to_uint64(); + + /// this is the rshares voting for or against the post + int64_t rshares = o.weight < 0 ? -abs_rshares : abs_rshares; + + if( comment.cashout_time.sec_since_epoch() - db().head_block_time().sec_since_epoch() < STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD ) + FC_ASSERT( itr->rshares > rshares, "Change of vote is within lockout period and increases net_rshares to comment." ); + + db().modify( voter, [&]( account_object& a ){ + a.voting_power = current_power - used_power; + a.last_vote_time = db().head_block_time(); + }); + + /// if the current net_rshares is less than 0, the post is getting 0 rewards so it is not factored into total rshares^2 + fc::uint128_t old_rshares = std::max(comment.net_rshares.value, int64_t(0)); + auto old_abs_rshares = comment.abs_rshares.value; + + fc::uint128_t cur_cashout_time_sec = comment.cashout_time.sec_since_epoch(); + fc::uint128_t new_cashout_time_sec = db().head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS; + auto avg_cashout_sec = (cur_cashout_time_sec * old_abs_rshares + new_cashout_time_sec * abs_rshares ) / (comment.abs_rshares.value + abs_rshares ); db().modify( comment, [&]( comment_object& c ) { - c.total_vote_weight -= itr->weight; c.net_rshares -= itr->rshares; + c.net_rshares += rshares; + c.abs_rshares += abs_rshares; + c.cashout_time = fc::time_point_sec( ) + fc::seconds(avg_cashout_sec.to_uint64()); c.total_vote_weight -= itr->weight; }); + old_rshares = comment.net_rshares.value - rshares + itr->rshares; // Get original old_rshares; + old_rshares *= old_rshares; + fc::uint128_t new_rshares = std::max( comment.net_rshares.value, int64_t(0)); + new_rshares *= new_rshares; + db().modify( *itr, [&]( comment_vote_object& cv ) { - cv.rshares = 0; + cv.rshares = rshares; + cv.vote_percent = o.weight; + cv.last_update = db().head_block_time(); cv.weight = 0; }); + + db().adjust_rshares2( comment, old_rshares, new_rshares ); } } diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 1da5e584e1..59363bff42 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -649,24 +649,6 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( itr != vote_idx.end() ); validate_database(); - BOOST_TEST_MESSAGE( "--- Test preventing repeated voting" ); - op.weight = STEEMIT_100_PERCENT / 2; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back( op ); - tx.sign( alice_private_key, db.get_chain_id() ); - - STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); - - itr = vote_idx.find( std::make_tuple( alice_comment.id, alice.id ) ); - - BOOST_REQUIRE_EQUAL( alice.voting_power, old_voting_power - ( old_voting_power / 20 ) ); - BOOST_REQUIRE( alice.last_vote_time == db.head_block_time() ); - BOOST_REQUIRE_EQUAL( alice_comment.net_rshares.value, alice.vesting_shares.amount.value * ( old_voting_power - alice.voting_power ) / STEEMIT_100_PERCENT ); - BOOST_REQUIRE( alice_comment.cashout_time == db.head_block_time() + fc::seconds( STEEMIT_CASHOUT_WINDOW_SECONDS ) ); - BOOST_REQUIRE( itr != vote_idx.end() ); - validate_database(); - BOOST_TEST_MESSAGE( "--- Test reduced power for quick voting" ); old_voting_power = alice.voting_power; @@ -790,52 +772,49 @@ BOOST_AUTO_TEST_CASE( vote_apply ) validate_database(); - BOOST_TEST_MESSAGE( "--- Testing removing votes for hardfork 3" ); db.set_hardfork( STEEMIT_HARDFORK_3 ); - BOOST_TEST_MESSAGE( "--- Test failure when modifying a vote to a non-zero weight" ); + BOOST_TEST_MESSAGE( "--- Test changing a positive vote to a different positive vote" ); - auto alice_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, db.get_account( "alice" ).id ) ); + auto new_alice = db.get_account( "alice" ); + auto alice_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, new_alice.id ) ); + auto old_vote_rshares = alice_bob_vote->rshares; + auto old_vote_weight = alice_bob_vote->weight; old_net_rshares = new_bob_comment.net_rshares.value; auto old_abs_rshares = new_bob_comment.abs_rshares; - auto old_vote_weights = new_bob_comment.total_vote_weight; + auto old_total_vote_weight = new_bob_comment.total_vote_weight; old_cashout_time = new_bob_comment.cashout_time; - auto vote_rshares = alice_bob_vote->rshares; - auto vote_weight = alice_bob_vote->weight; - auto alice_vote_power = db.get_account( "alice" ).voting_power; - - idump( (*alice_bob_vote) ); + auto alice_voting_power = new_alice.voting_power - ( STEEMIT_1_PERCENT * 25 * new_alice.voting_power ) / STEEMIT_100_PERCENT / 20; + auto new_rshares = ( ( fc::uint128_t ( new_alice.voting_power - alice_voting_power ) * new_alice.vesting_shares.amount.value ) / STEEMIT_100_PERCENT ).to_uint64(); op.voter = "alice"; + op.weight = STEEMIT_1_PERCENT * 25; op.author = "bob"; op.permlink = "foo"; - op.weight = STEEMIT_1_PERCENT * 50; - tx.operations.clear(); - tx.signatures.clear(); - tx.operations.push_back( op ); - tx.sign( alice_private_key, db.get_chain_id() ); - STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); - - BOOST_TEST_MESSAGE( "--- Test removing a positive vote" ); - - op.weight = 0; tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back( op ); tx.sign( alice_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - vote_rshares ); - BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares - vote_rshares ); - BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_vote_weights - vote_weight ); - BOOST_REQUIRE( new_bob_comment.cashout_time == old_cashout_time ); + idump( (new_bob_comment.net_rshares)(old_net_rshares)(old_vote_rshares)(new_rshares) ); + + BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - old_vote_rshares + new_rshares ); + BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares + new_rshares ); + BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_total_vote_weight - old_vote_weight ); + BOOST_REQUIRE( new_bob_comment.cashout_time == fc::time_point_sec( ( old_cashout_time.sec_since_epoch() * old_abs_rshares.value + ( db.head_block_time().sec_since_epoch() + STEEMIT_CASHOUT_WINDOW_SECONDS ) * new_rshares ) / ( old_abs_rshares.value + new_rshares ) ) ); BOOST_REQUIRE( alice_bob_vote->weight == 0 ); - BOOST_REQUIRE( alice_bob_vote->rshares == 0 ); - BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_vote_power ); + BOOST_REQUIRE( alice_bob_vote->rshares == new_rshares ); + BOOST_REQUIRE( alice_bob_vote->last_update == db.head_block_time() ); + BOOST_REQUIRE( alice_bob_vote->vote_percent == op.weight ); + BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_voting_power ); validate_database(); - BOOST_TEST_MESSAGE( "--- Test removing a negative vote" ); +/* + BOOST_TEST_MESSAGE( "--- Test changing a positive vote to a negative vote" ); + + BOOST_TEST_MESSAGE( "--- Test changing a negative vote to a less negative vote" ); auto sam_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, db.get_account( "sam" ).id ) ); old_net_rshares = new_bob_comment.net_rshares.value; @@ -860,6 +839,17 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( db.get_account( "sam" ).voting_power == sam_vote_power ); validate_database(); + + BOOST_TEST_MESSAGE( "--- Test changing a negative vote to a positive vote" ); + + BOOST_TEST_MESSAGE( "--- Test changing a vote to 0 weight" ); + + BOOST_TEST_MESSAGE( "--- Test failure when increasing rshares within lockout period" ); + + BOOST_TEST_MESSAGE( "--- Test success when reducing rshares within lockout period" ); + + BOOST_TEST_MESSAGE( "--- Test success with a new vote within lockout period" ); + */ } } FC_LOG_AND_RETHROW() From ab8b6a294bf95336f861d9cf06a6b3a5e380bfaa Mon Sep 17 00:00:00 2001 From: Reverse Flash Date: Thu, 12 May 2016 16:27:55 -0400 Subject: [PATCH 17/20] fixing crashing wallet --- libraries/app/database_api.cpp | 37 +++++++++++++++++++ .../app/include/steemit/app/database_api.hpp | 5 +++ libraries/wallet/wallet.cpp | 9 ++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index f5dce7014a..55b0d2db82 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -871,6 +871,43 @@ vector database_api::get_discussions_by_last_active( string start_pa return result; } +vector database_api::get_discussions_by_votes( string start_parent_author, string start_permlink, uint32_t limit )const { + + vector result; + idump((start_parent_author)(start_permlink)(limit) ); + /* + const auto& last_activity_idx = my->_db.get_index_type< comment_stats_index >().indices().get< by_net_votes >(); + + auto itr = last_activity_idx.begin(); + + + if( start_permlink.size() ) { + const auto& start_comment = my->_db.get_comment( start_parent_author, start_permlink ); + itr = last_activity_idx.iterator_to( start_comment.stats(my->_db) ); + } + else if( start_parent_author.size() ) { + const auto& start_author = my->_db.get_account( start_parent_author ); + itr = last_activity_idx.lower_bound( boost::make_tuple( start_author.get_id(), std::numeric_limits::max(), object_id_type() ) ); + } + + while( itr != last_activity_idx.end() && result.size() < limit ) { + const auto& c = itr->comment_id(my->_db); + result.push_back( c ); + set_pending_payout(result.back()); + result.back().active_votes = get_active_votes( c.author, c.permlink ); + ++itr; + } + */ + return result; +} + + +vector database_api::get_discussions_in_category_by_votes( string category, string start_auth, string start_permlink, uint32_t limit )const { + + vector result; + return result; +} + vector database_api::get_discussions_in_category_by_last_active( string category, string start_auth, string start_permlink, uint32_t limit )const { const auto& last_activity_in_category = my->_db.get_index_type< comment_index >().indices().get< by_active_in_category >(); diff --git a/libraries/app/include/steemit/app/database_api.hpp b/libraries/app/include/steemit/app/database_api.hpp index 7e4487cfff..8ab2afdcaa 100755 --- a/libraries/app/include/steemit/app/database_api.hpp +++ b/libraries/app/include/steemit/app/database_api.hpp @@ -306,6 +306,9 @@ class database_api vector get_discussions_by_last_active( string start_author, string start_permlink, uint32_t limit )const; vector get_discussions_in_category_by_last_active( string category, string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_by_votes( string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_in_category_by_votes( string category, string start_author, string start_permlink, uint32_t limit )const; + vector get_discussions_by_created( string start_author, string start_permlink, uint32_t limit )const; vector get_discussions_in_category_by_created( string category, string start_author, string start_permlink, uint32_t limit )const; @@ -404,9 +407,11 @@ FC_API(steemit::app::database_api, (get_discussions_in_category_by_total_pending_payout) (get_discussions_by_last_update) (get_discussions_by_last_active) + (get_discussions_by_votes) (get_discussions_by_created) (get_discussions_in_category_by_last_update) (get_discussions_in_category_by_last_active) + (get_discussions_in_category_by_votes) (get_discussions_in_category_by_created) (get_discussions_by_author_before_date) (get_discussions_by_cashout_time) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 612cf63df1..40a0d125ab 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -241,14 +241,19 @@ class wallet_api_impl : self( s ), _remote_api( rapi ), _remote_db( rapi->get_api_by_name("database_api")->as< database_api >() ), - _remote_net_broadcast( rapi->get_api_by_name("network_broadcast_api")->as< network_broadcast_api >() ), - _remote_message_api( rapi->get_api_by_name("private_message_api")->as< private_message_api >() ) + _remote_net_broadcast( rapi->get_api_by_name("network_broadcast_api")->as< network_broadcast_api >() ) { init_prototype_ops(); _wallet.ws_server = initial_data.ws_server; _wallet.ws_user = initial_data.ws_user; _wallet.ws_password = initial_data.ws_password; + + try { + _remote_message_api = rapi->get_api_by_name("private_message_api")->as< private_message_api >(); + } catch ( const fc::exception& e ) { + wlog( "error fetching private_message_api" ); + } } virtual ~wallet_api_impl() {} From 60a64ce1ca5166e2ede8509300b63c1d94361a87 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Thu, 12 May 2016 22:28:28 -0400 Subject: [PATCH 18/20] Node now runs properly with default plugins --- libraries/app/application.cpp | 1 - libraries/wallet/wallet.cpp | 32 +++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 140e7c3625..63ec91c28e 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -333,7 +333,6 @@ namespace detail { wild_access.allowed_apis.push_back( "network_broadcast_api" ); wild_access.allowed_apis.push_back( "history_api" ); wild_access.allowed_apis.push_back( "crypto_api" ); - wild_access.allowed_apis.push_back( "private_message_api" ); _apiaccess.permission_map["*"] = wild_access; } diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 40a0d125ab..6112ad0dbe 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -248,12 +248,6 @@ class wallet_api_impl _wallet.ws_server = initial_data.ws_server; _wallet.ws_user = initial_data.ws_user; _wallet.ws_password = initial_data.ws_password; - - try { - _remote_message_api = rapi->get_api_by_name("private_message_api")->as< private_message_api >(); - } catch ( const fc::exception& e ) { - wlog( "error fetching private_message_api" ); - } } virtual ~wallet_api_impl() {} @@ -836,14 +830,26 @@ class wallet_api_impl } catch( const fc::exception& e ) { - std::cerr << "\nCouldn't get network node API. You probably are not configured\n" - "to access the network API on the witness_node you are\n" - "connecting to. Please follow the instructions in README.md to set up an apiaccess file.\n" - "\n"; + elog( "Couldn't get network node API" ); throw(e); } } + void use_remote_message_api() + { + if( _remote_message_api.valid() ) + return; + try + { + _remote_message_api = _remote_api->get_api_by_name("private_message_api")->as< private_message_api >(); + } + catch( const fc::exception& e ) + { + elog( "Couldn't get network node API" ); + throw(e); + } + } + void network_add_nodes( const vector& nodes ) { use_network_node_api(); @@ -884,8 +890,8 @@ class wallet_api_impl fc::api _remote_api; fc::api _remote_db; fc::api _remote_net_broadcast; - fc::api _remote_message_api; optional< fc::api > _remote_net_node; + optional< fc::api > _remote_message_api; flat_map _prototype_ops; @@ -1859,7 +1865,7 @@ message_body wallet_api::try_decrypt_message( const message_object& mo ) { vector wallet_api::get_inbox( string account, fc::time_point newest, uint32_t limit ) { FC_ASSERT( !is_locked() ); vector result; - auto remote_result = my->_remote_message_api->get_inbox( account, newest, limit ); + auto remote_result = (*my->_remote_message_api)->get_inbox( account, newest, limit ); for( const auto& item : remote_result ) { result.emplace_back( item ); result.back().message = try_decrypt_message( item ); @@ -1870,7 +1876,7 @@ vector wallet_api::get_inbox( string account, fc::tim vector wallet_api::get_outbox( string account, fc::time_point newest, uint32_t limit ) { FC_ASSERT( !is_locked() ); vector result; - auto remote_result = my->_remote_message_api->get_outbox( account, newest, limit ); + auto remote_result = (*my->_remote_message_api)->get_outbox( account, newest, limit ); for( const auto& item : remote_result ) { result.emplace_back( item ); result.back().message = try_decrypt_message( item ); From b77797750ad3d9f6c4f77b071317d9439ae4fead Mon Sep 17 00:00:00 2001 From: Michael Vandeberg Date: Fri, 13 May 2016 10:10:08 -0400 Subject: [PATCH 19/20] Finish tests and some misc cleanup #22 --- .gitignore | 5 +++ libraries/chain/database.cpp | 10 +++++ libraries/chain/steem_evaluator.cpp | 2 +- tests/common/database_fixture.hpp | 2 +- tests/tests/operation_tests.cpp | 59 ++++++++++++++++++++++++++--- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 6227c1bc27..5490abcece 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ programs/js_operation_serializer/js_operation_serializer programs/steemd/steemd programs/steemd/test programs/delayed_node +programs/build_helpers/cat-parts +programs/size_checker/size_checker +programs/util/get_dev_key +programs/util/inflation_model tests/app_test tests/chain_bench @@ -39,3 +43,4 @@ witness_node_data_dir *.pyc *.pyo +*.egg-info/ diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 717bc8c975..d7f0a60b36 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2587,7 +2587,9 @@ void database::process_hardforks() switch( hardforks.last_hardfork + 1) { case STEEMIT_HARDFORK_0_1_0: + #ifndef IS_TEST_NET elog( "HARDFORK 1" ); + #endif perform_vesting_share_split( 1000000 ); #ifdef IS_TEST_NET { @@ -2601,19 +2603,27 @@ void database::process_hardforks() #endif break; case STEEMIT_HARDFORK_0_2_0: + #ifndef IS_TEST_NET elog( "HARDFORK 2" ); + #endif retally_witness_votes(); break; case STEEMIT_HARDFORK_0_3_0: + #ifndef IS_TEST_NET elog( "HARDFORK 3" ); + #endif retally_witness_votes(); break; case STEEMIT_HARDFORK_0_4_0: + #ifndef IS_TEST_NET elog( "HARDFORK 4" ); + #endif reset_virtual_schedule_time(); break; case STEEMIT_HARDFORK_0_5_0: + #ifndef IS_TEST_NET elog( "HARDFORK 5" ); + #endif break; default: break; diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index f51a12897b..cd530dde73 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -652,7 +652,7 @@ void vote_evaluator::do_apply( const vote_operation& o ) auto effective_cashout_time = std::max( STEEMIT_FIRST_CASHOUT_TIME, comment.cashout_time ); - if( effective_cashout_time.sec_since_epoch() - db().head_block_time().sec_since_epoch() < STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD ) + if( effective_cashout_time.sec_since_epoch() - db().head_block_time().sec_since_epoch() <= STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD ) FC_ASSERT( itr->rshares > rshares, "Change of vote is within lockout period and increases net_rshares to comment." ); db().modify( voter, [&]( account_object& a ){ diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 8b3c37f919..fd72055da5 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -10,7 +10,7 @@ #define INITIAL_TEST_SUPPLY (10000000000ll) using namespace graphene::db; -extern uint32_t STEEMIT_TESTING_GENESIS_TIMESTAMP; +extern uint32_t ( STEEMIT_TESTING_GENESIS_TIMESTAMP ); #define PUSH_TX \ steemit::chain::test::_push_transaction diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 0af4cbd9cf..f0f0b340be 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -800,7 +800,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) validate_database(); - BOOST_TEST_MESSAGE( "--- Test changing a positive vote to a different positive vote" ); + BOOST_TEST_MESSAGE( "--- Test increasing vote rshares" ); auto new_alice = db.get_account( "alice" ); auto alice_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, new_alice.id ) ); @@ -835,7 +835,7 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_voting_power ); validate_database(); - BOOST_TEST_MESSAGE( "--- Test changing a positive vote to a negative vote" ); + BOOST_TEST_MESSAGE( "--- Test decreasing vote rshares" ); old_vote_rshares = new_rshares; old_net_rshares = new_bob_comment.net_rshares.value; @@ -864,18 +864,67 @@ BOOST_AUTO_TEST_CASE( vote_apply ) BOOST_REQUIRE( alice_bob_vote->last_update == db.head_block_time() ); BOOST_REQUIRE( alice_bob_vote->vote_percent == op.weight ); BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_voting_power ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test changing a vote to 0 weight (aka: removing a vote)" ); + + old_vote_rshares = -1 * new_rshares; + old_net_rshares = new_bob_comment.net_rshares.value; + old_abs_rshares = new_bob_comment.abs_rshares.value; + old_cashout_time = new_bob_comment.cashout_time.sec_since_epoch(); + new_rshares = 0; + op.weight = 0; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( alice_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + alice_bob_vote = vote_idx.find( std::make_tuple( new_bob_comment.id, new_alice.id ) ); + + BOOST_REQUIRE( new_bob_comment.net_rshares == old_net_rshares - old_vote_rshares ); + BOOST_REQUIRE( new_bob_comment.abs_rshares == old_abs_rshares ); + BOOST_REQUIRE( new_bob_comment.total_vote_weight == old_total_vote_weight ); + BOOST_REQUIRE( new_bob_comment.cashout_time == fc::time_point_sec( old_cashout_time.to_uint64() ) ); + BOOST_REQUIRE( alice_bob_vote->weight == 0 ); + BOOST_REQUIRE( alice_bob_vote->rshares == 0 ); + BOOST_REQUIRE( alice_bob_vote->last_update == db.head_block_time() ); + BOOST_REQUIRE( alice_bob_vote->vote_percent == op.weight ); + BOOST_REQUIRE( db.get_account( "alice" ).voting_power == alice_voting_power ); validate_database(); -/* - BOOST_TEST_MESSAGE( "--- Test changing a vote to 0 weight" ); BOOST_TEST_MESSAGE( "--- Test failure when increasing rshares within lockout period" ); + generate_blocks( fc::time_point_sec( new_bob_comment.cashout_time.sec_since_epoch() - STEEMIT_VOTE_CHANGE_LOCKOUT_PERIOD + STEEMIT_BLOCK_INTERVAL ), true ); + + op.weight = STEEMIT_100_PERCENT; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + 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 success when reducing rshares within lockout period" ); + op.weight = -1 * STEEMIT_100_PERCENT; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( alice_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + validate_database(); + BOOST_TEST_MESSAGE( "--- Test success with a new vote within lockout period" ); - */ + op.weight = STEEMIT_100_PERCENT; + op.voter = "sam"; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( sam_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + validate_database(); } } FC_LOG_AND_RETHROW() From 5012ebe229f7d12682726e3d7f91e8cc6ca33bca Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Fri, 13 May 2016 15:14:19 -0400 Subject: [PATCH 20/20] Dispatch pre-0.5 validate_permlink() calls to old implementation --- libraries/chain/steem_evaluator.cpp | 36 ++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 5f12bef328..7cda736215 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -12,13 +12,32 @@ namespace steemit { namespace chain { using fc::uint128_t; +inline void validate_permlink( const string& permlink ) +{ + FC_ASSERT( permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH ); + + for( auto c : permlink ) + { + switch( c ) + { + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': + case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': + case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + case '-': + break; + default: + FC_ASSERT( !"Invalid permlink character:", "${s}", ("s", std::string() + c ) ); + } + } +} + /** * Allow GROUP / TOPIC */ -void inline validate_permlink( string permlink, const database& db ) +template< bool allow_slash > +void validate_permlink_0_5( const string& permlink ) { - bool allow_slash = db.has_hardfork( STEEMIT_HARDFORK_0_5_0 ); - FC_ASSERT( permlink.size() > STEEMIT_MIN_PERMLINK_LENGTH && permlink.size() < STEEMIT_MAX_PERMLINK_LENGTH ); int char_count = 0; @@ -175,10 +194,15 @@ void comment_evaluator::do_apply( const comment_operation& o ) const auto& new_comment = db().create< comment_object >( [&]( comment_object& com ) { - if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) + if( db().has_hardfork( STEEMIT_HARDFORK_0_5_0 ) ) + { + validate_permlink_0_5( o.parent_permlink ); + validate_permlink_0_5( o.permlink ); + } + else if( db().has_hardfork( STEEMIT_HARDFORK_0_1_0 ) ) { - validate_permlink( o.parent_permlink, db() ); - validate_permlink( o.permlink, db() ); + validate_permlink( o.parent_permlink ); + validate_permlink( o.permlink ); } if ( o.parent_author.size() == 0 )