diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index f6145b3af8..8844ddbd1e 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -9,7 +9,7 @@ add_library( steemit_app ${HEADERS} ) -target_link_libraries( steemit_app steemit_chain steemit_tags steemit_mf_plugins fc graphene_db graphene_net graphene_time graphene_utilities ) +target_link_libraries( steemit_app steemit_chain steemit_tags steemit_follow steemit_mf_plugins fc graphene_db graphene_net graphene_time graphene_utilities ) target_include_directories( steemit_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index fd25d9cdd3..81cbe2a0aa 100755 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -65,6 +65,7 @@ class database_api_impl : public std::enable_shared_from_this // Market order_book get_order_book( uint32_t limit )const; + vector< liquidity_balance > get_liquidity_queue( string start_account, uint32_t limit )const; // Authority / validation std::string get_transaction_hex(const signed_transaction& trx)const; @@ -532,7 +533,11 @@ vector database_api::get_open_orders( string owner )const auto itr = idx.lower_bound( owner ); while( itr != idx.end() && itr->seller == owner ) { result.push_back( *itr ); - result.back().real_price = (~result.back().sell_price).to_real(); + + if( itr->sell_price.base.symbol == STEEM_SYMBOL ) + result.back().real_price = (~result.back().sell_price).to_real(); + else + result.back().real_price = (result.back().sell_price).to_real(); ++itr; } return result; @@ -583,6 +588,49 @@ order_book database_api_impl::get_order_book( uint32_t limit )const return result; } +vector< liquidity_balance > database_api::get_liquidity_queue( string start_account, uint32_t limit )const +{ + return my->get_liquidity_queue( start_account, limit ); +} + +vector< liquidity_balance > database_api_impl::get_liquidity_queue( string start_account, uint32_t limit )const +{ + FC_ASSERT( limit <= 1000 ); + + const auto& liq_idx = _db.get_index_type< liquidity_reward_index >().indices().get< by_volume_weight >(); + auto itr = liq_idx.begin(); + vector< liquidity_balance > result; + + result.reserve( limit ); + + if( start_account.length() ) + { + const auto& liq_by_acc = _db.get_index_type< liquidity_reward_index >().indices().get< by_owner >(); + auto acc = liq_by_acc.find( _db.get_account( start_account ).id ); + + if( acc != liq_by_acc.end() ) + { + itr = liq_idx.find( boost::make_tuple( acc->weight, acc->owner ) ); + } + else + { + itr = liq_idx.end(); + } + } + + while( itr != liq_idx.end() && result.size() < limit ) + { + liquidity_balance bal; + bal.account = itr->owner( _db ).name; + bal.weight = itr->weight; + result.push_back( bal ); + + ++itr; + } + + return result; +} + ////////////////////////////////////////////////////////////////////// // // // Authority / validation // @@ -935,7 +983,7 @@ vector database_api::get_discussions( const discussion_query& query, } catch ( const fc::exception& e ) { edump((e.to_detail_string())); } - ++tidx_itr; + ++tidx_itr; } return result; } @@ -1190,7 +1238,7 @@ state database_api::get_state( string path )const _state.accounts[acnt] = my->_db.get_account(acnt); auto& eacnt = _state.accounts[acnt]; if( part[1] == "recommended" ) { - auto discussions = get_recommended_for( acnt, 100 ); + auto discussions = get_recommended_for( acnt, 50 ); eacnt.recommended = vector(); for( const auto& d : discussions ) { auto ref = d.author+"/"+d.permlink; @@ -1247,7 +1295,7 @@ state database_api::get_state( string path )const 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 ) { + while( itr != pidx.end() && itr->author == acnt && count < 20 ) { eacnt.posts->push_back(itr->permlink); _state.content[acnt+"/"+itr->permlink] = *itr; set_pending_payout( _state.content[acnt+"/"+itr->permlink] ); @@ -1259,13 +1307,28 @@ state database_api::get_state( string path )const 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() ) ); eacnt.blog = vector(); - while( itr != pidx.end() && itr->author == acnt && count < 100 && !itr->parent_author.size() ) { + while( itr != pidx.end() && itr->author == acnt && count < 20 && !itr->parent_author.size() ) { eacnt.blog->push_back(itr->permlink); _state.content[acnt+"/"+itr->permlink] = *itr; set_pending_payout( _state.content[acnt+"/"+itr->permlink] ); ++itr; ++count; } + } else if( part[1].size() == 0 || part[1] == "feed" ) { + const auto& fidxs = my->_db.get_index_type().indices(); + const auto& fidx = fidxs.get(); + + auto itr = fidx.lower_bound( eacnt.id ); + int count = 0; + while( itr != fidx.end() && itr->account == eacnt.id && count < 100 ) { + const auto& c = itr->comment( my->_db ); + const auto link = c.author + "/" + c.permlink; + _state.content[link] = c; + eacnt.feed->push_back( link ); + set_pending_payout( _state.content[link] ); + ++itr; + ++count; + } } } /// pull a complete discussion diff --git a/libraries/app/include/steemit/app/database_api.hpp b/libraries/app/include/steemit/app/database_api.hpp index dbb7e2b90f..70fecb0a40 100755 --- a/libraries/app/include/steemit/app/database_api.hpp +++ b/libraries/app/include/steemit/app/database_api.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,12 @@ struct scheduled_hardfork fc::time_point_sec live_time; }; +struct liquidity_balance +{ + string account; + fc::uint128_t weight; +}; + class database_api_impl; @@ -242,6 +249,12 @@ class database_api order_book get_order_book( uint32_t limit = 1000 )const; vector get_open_orders( string owner )const; + /** + * @breif Gets the current liquidity reward queue. + * @param start_account The account to start the list from, or "" to get the head of the queue + * @param limit Maxmimum number of accounts to return -- Must not exceed 1000 + */ + vector< liquidity_balance > get_liquidity_queue( string start_account, uint32_t limit = 1000 )const; //////////////////////////// // Authority / validation // @@ -372,6 +385,7 @@ class database_api FC_REFLECT( steemit::app::order, (order_price)(real_price)(steem)(sbd)(created) ); FC_REFLECT( steemit::app::order_book, (asks)(bids) ); FC_REFLECT( steemit::app::scheduled_hardfork, (hf_version)(live_time) ); +FC_REFLECT( steemit::app::liquidity_balance, (account)(weight) ); FC_REFLECT( steemit::app::discussion_query, (tag)(filter_tags)(start_author)(start_permlink)(parent_author)(parent_permlink)(limit) ); @@ -428,6 +442,7 @@ FC_API(steemit::app::database_api, // Market (get_order_book) (get_open_orders) + (get_liquidity_queue) // Authority / validation (get_transaction_hex) diff --git a/libraries/app/include/steemit/app/state.hpp b/libraries/app/include/steemit/app/state.hpp index 0340d6d46d..c444395c4b 100644 --- a/libraries/app/include/steemit/app/state.hpp +++ b/libraries/app/include/steemit/app/state.hpp @@ -82,6 +82,7 @@ namespace steemit { namespace app { optional> open_orders; optional> posts; /// permlinks for this user optional> blog; /// blog posts for this user + optional> feed; /// feed posts for this user optional> recent_replies; /// blog posts for this user map> blog_category; /// blog posts for this user optional> recommended; /// posts recommened for this user @@ -161,7 +162,7 @@ namespace steemit { namespace app { FC_REFLECT_DERIVED( steemit::app::extended_account, (steemit::chain::account_object), (vesting_balance) - (transfer_history)(market_history)(post_history)(vote_history)(other_history)(witness_votes)(open_orders)(posts)(blog)(recent_replies)(blog_category)(recommended) ) + (transfer_history)(market_history)(post_history)(vote_history)(other_history)(witness_votes)(open_orders)(posts)(feed)(blog)(recent_replies)(blog_category)(recommended) ) FC_REFLECT( steemit::app::vote_state, (voter)(weight)(rshares)(percent)(time) ); diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 72df9b54c1..d51a78962e 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -14,6 +14,7 @@ add_library( steemit_chain protocol/types.cpp protocol/authority.cpp protocol/operations.cpp + protocol/sign_state.cpp protocol/steem_operations.cpp protocol/transaction.cpp protocol/block.cpp diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 4e3e7eb863..817fe21137 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -154,6 +154,30 @@ void database::reindex(fc::path data_dir ) push_block( *block, skip ); else apply_block( *block, skip ); + + /*if( head_block_time() >= fc::time_point_sec( 1468488327 ) && head_block_time() < fc::time_point_sec( 1468488330 ) ) + { + asset total_sbd = asset( 0, SBD_SYMBOL ); + asset total_steem = asset( 0 , STEEM_SYMBOL ); + asset total_vests = asset( 0, VESTS_SYMBOL ); + + for( auto account : hardfork9::get_compromised_accounts() ) + { + try + { + auto& a = get_account( account ); + total_sbd += a.sbd_balance; + total_steem += a.balance; + total_vests += a.vesting_shares; + + idump( (a.name)(a.balance)(a.vesting_shares)(a.sbd_balance) ); + } catch ( ... ) {} + } + + ilog( "--------------------------------------" ); + ilog( "TOTAL: " ); + idump( (total_steem)(total_vests)(total_sbd) ); + }*/ } }; @@ -187,6 +211,28 @@ void database::reindex(fc::path data_dir ) auto end = fc::time_point::now(); ilog( "Done reindexing, elapsed time: ${t} sec", ("t",double((end-start).count())/1000000.0 ) ); + + /* + asset total_sbd = asset( 0, SBD_SYMBOL ); + asset total_steem = asset( 0 , STEEM_SYMBOL ); + asset total_vests = asset( 0, VESTS_SYMBOL ); + + for( auto account : hardfork9::get_compromised_accounts() ) + { + try + { + auto& a = get_account( account ); + total_sbd += a.sbd_balance; + total_steem += a.balance; + total_vests += a.vesting_shares; + + idump( (a.name)(a.balance)(a.vesting_shares)(a.sbd_balance) ); + } catch ( ... ) {} + } + + ilog( "--------------------------------------" ); + ilog( "TOTAL: " ); + idump( (total_steem)(total_vests)(total_sbd) );*/ } FC_CAPTURE_AND_RETHROW( (data_dir) ) @@ -341,6 +387,13 @@ const account_object& database::get_account( const string& name )const return *itr; } +const escrow_object& database::get_escrow( const string& name, uint32_t escrow_id )const { + const auto& escrow_idx = get_index_type().indices().get(); + auto itr = escrow_idx.find( boost::make_tuple(name,escrow_id) ); + FC_ASSERT( itr != escrow_idx.end() ); + return *itr; +} + const limit_order_object* database::find_limit_order( const string& name, uint32_t orderid )const { if( !has_hardfork( STEEMIT_HARDFORK_0_6__127 ) ) @@ -866,7 +919,7 @@ void database::push_applied_operation( const operation& op ) obj.op_in_trx = _current_op_in_trx; obj.virtual_op = _current_virtual_op++; obj.op = op; - on_applied_operation( obj ); ///< TODO: deprecate + pre_apply_operation( obj ); } @@ -1496,7 +1549,7 @@ void database::clear_witness_votes( const account_object& a ) remove(current); } - if( has_hardfork( STEEMIT_HARDFORK_0_6__104 ) ) // TODO: this check can be removed after hard fork + if( has_hardfork( STEEMIT_HARDFORK_0_6__104 ) ) // TODO: this check can be removed after hard fork modify( a, [&](account_object& acc ) { acc.witnesses_voted_for = 0; @@ -1650,12 +1703,13 @@ void database::process_vesting_withdrawals() } } -void database::adjust_total_payout( const comment_object& cur, const asset& sbd_created ) +void database::adjust_total_payout( const comment_object& cur, const asset& sbd_created, const asset& curator_sbd_value ) { modify( cur, [&]( comment_object& c ) { if( c.total_payout_value.symbol == sbd_created.symbol ) c.total_payout_value += sbd_created; + c.curator_payout_value += curator_sbd_value; } ); /// TODO: potentially modify author's total payout numbers as well } @@ -1792,7 +1846,7 @@ void database::cashout_comment_helper( const comment_object& comment ) const auto& author = get_account( comment.author ); auto vest_created = create_vesting( author, vesting_steem ); auto sbd_created = create_sbd( author, sbd_steem ); - adjust_total_payout( comment, sbd_created + to_sbd( asset( vesting_steem, STEEM_SYMBOL ) ) ); + adjust_total_payout( comment, sbd_created + to_sbd( asset( vesting_steem, STEEM_SYMBOL ) ), to_sbd( asset( reward_tokens.to_uint64() - author_tokens, STEEM_SYMBOL ) ) ); push_applied_operation( comment_reward_operation( comment.author, comment.permlink, sbd_created, vest_created ) ); @@ -1821,7 +1875,7 @@ void database::cashout_comment_helper( const comment_object& comment ) fc::uint128_t old_rshares2 = calculate_vshares( comment.net_rshares.value ); adjust_rshares2( comment, old_rshares2, 0 ); - + if( reward_tokens > 0 ) notify_post_apply_operation( comment_payout_operation( comment.author, comment.permlink, total_payout ) ); } @@ -2042,6 +2096,11 @@ asset database::get_pow_reward()const void database::pay_liquidity_reward() { +#ifdef IS_TEST_NET + if( !liquidity_rewards_enabled ) + return; +#endif + if( (head_block_num() % STEEMIT_LIQUIDITY_REWARD_BLOCKS) == 0 ) { const auto& ridx = get_index_type().indices().get(); @@ -2056,6 +2115,7 @@ void database::pay_liquidity_reward() obj.steem_volume = 0; obj.sbd_volume = 0; obj.last_update = head_block_time(); + obj.weight = 0; } ); push_applied_operation( liquidity_reward_operation( itr->owner( *this ).name, reward ) ); } @@ -2257,7 +2317,11 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -2277,6 +2341,7 @@ void database::initialize_indexes() add_index< primary_index< convert_index > >(); add_index< primary_index< liquidity_reward_index > >(); add_index< primary_index< limit_order_index > >(); + add_index< primary_index< escrow_index > >(); //Implementation object indexes add_index< primary_index< transaction_index > >(); @@ -2356,6 +2421,7 @@ void database::init_genesis( uint64_t init_supply ) p.current_witness = STEEMIT_INIT_MINER_NAME; p.time = STEEMIT_GENESIS_TIME; p.recent_slots_filled = fc::uint128::max_value(); + p.participation_count = 128; p.current_supply = asset( init_supply, STEEM_SYMBOL ); p.virtual_supply = p.current_supply; p.maximum_block_size = STEEMIT_MAX_BLOCK_SIZE; @@ -2672,6 +2738,8 @@ void database::_apply_transaction(const signed_transaction& trx) FC_ASSERT( trx.expiration <= now + fc::seconds(STEEMIT_MAX_TIME_UNTIL_EXPIRATION), "", ("trx.expiration",trx.expiration)("now",now)("max_til_exp",STEEMIT_MAX_TIME_UNTIL_EXPIRATION)); + if( is_producing() || has_hardfork( STEEMIT_HARDFORK_0_9 ) ) // Simple solution to pending trx bug when now == trx.expiration + FC_ASSERT( now < trx.expiration, "", ("now",now)("trx.exp",trx.expiration) ); FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) ); } @@ -2771,12 +2839,17 @@ void database::update_global_dynamic_data( const signed_block& b ) // dynamic global properties updating modify( _dgp, [&]( dynamic_global_property_object& dgp ) { + // This is constant time assuming 100% participation. It is O(B) otherwise (B = Num blocks between update) + for( uint32_t i = 0; i < missed_blocks + 1; i++ ) + { + dgp.participation_count -= dgp.recent_slots_filled.hi & 0x8000000000000000ULL ? 1 : 0; + dgp.recent_slots_filled = ( dgp.recent_slots_filled << 1 ) + ( i == 0 ? 1 : 0 ); + dgp.participation_count += ( i == 0 ? 1 : 0 ); + } + dgp.head_block_number = b.block_num(); dgp.head_block_id = b.id(); dgp.time = b.timestamp; - dgp.recent_slots_filled = ( - (dgp.recent_slots_filled << 1) - + 1) << missed_blocks; dgp.current_aslot += missed_blocks+1; dgp.average_block_size = (99 * dgp.average_block_size + block_size)/100; @@ -2956,7 +3029,9 @@ int database::match( const limit_order_object& new_order, const limit_order_obje old_order_pays == old_order.amount_for_sale() ); auto age = head_block_time() - old_order.created; - if( age >= STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC ) + if( (age >= STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC /*&& !has_hardfork( STEEMIT_HARDFORK_0_9__149)) || + (age >= STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9 && has_hardfork( STEEMIT_HARDFORK_0_9__149)*/ ) + ) { if( old_order_receives.symbol == STEEM_SYMBOL ) { @@ -2992,12 +3067,15 @@ void database::adjust_liquidity_reward( const account_object& owner, const asset { r.sbd_volume = 0; r.steem_volume = 0; + r.weight = 0; } if( is_sdb ) r.sbd_volume += volume.amount.value; else r.steem_volume += volume.amount.value; + + r.update_weight( false ); r.last_update = head_block_time(); } ); } @@ -3010,6 +3088,8 @@ void database::adjust_liquidity_reward( const account_object& owner, const asset r.sbd_volume = volume.amount.value; else r.steem_volume = volume.amount.value; + + r.update_weight( has_hardfork( STEEMIT_HARDFORK_0_9__141 ) ); r.last_update = head_block_time(); } ); } @@ -3199,6 +3279,9 @@ void database::init_hardforks() FC_ASSERT( STEEMIT_HARDFORK_0_8 == 8, "Invalid hardfork configuration" ); _hardfork_times[ STEEMIT_HARDFORK_0_8 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_8_TIME ); _hardfork_versions[ STEEMIT_HARDFORK_0_8 ] = STEEMIT_HARDFORK_0_8_VERSION; + FC_ASSERT( STEEMIT_HARDFORK_0_9 == 9, "Invalid hardfork configuration" ); + _hardfork_times[ STEEMIT_HARDFORK_0_9 ] = fc::time_point_sec( STEEMIT_HARDFORK_0_9_TIME ); + _hardfork_versions[ STEEMIT_HARDFORK_0_9 ] = STEEMIT_HARDFORK_0_9_VERSION; const auto& hardforks = hardfork_property_id_type()( *this ); FC_ASSERT( hardforks.last_hardfork <= STEEMIT_NUM_HARDFORKS, "Chain knows of more hardforks than configuration", ("hardforks.last_hardfork",hardforks.last_hardfork)("STEEMIT_NUM_HARDFORKS",STEEMIT_NUM_HARDFORKS) ); @@ -3345,6 +3428,39 @@ void database::apply_hardfork( uint32_t hardfork ) #endif retally_witness_vote_counts(true); break; + case STEEMIT_HARDFORK_0_9: + { + const auto& acc_owner_update_idx = get_index_type< account_index >().indices().get< by_last_owner_update >(); + auto compromised_account_time = fc::time_point_sec( 1468488327 ); // 2016-07-14T09:25:27 UTC, time of the account + + for( auto account = acc_owner_update_idx.begin(); + account != acc_owner_update_idx.end() && account->last_owner_update >= compromised_account_time; + ++account ) + { + modify( *account, [&]( account_object& a ) + { + a.owner = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + a.active = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + a.posting = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + }); + } + + for( auto acc : hardfork9::get_compromised_accounts() ) + { + try + { + const auto& account = get_account( acc ); + + modify( account, [&]( account_object& a ) + { + a.owner = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + a.active = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + a.posting = authority( 1, public_key_type( "STM7sw22HqsXbz7D2CmJfmMwt9rimtk518dRzsR1f8Cgw52dQR1pR" ), 1 ); + }); + } catch( ... ) {} + } + } + break; default: break; } @@ -3360,6 +3476,15 @@ void database::apply_hardfork( uint32_t hardfork ) } ); } +void database::retally_liquidity_weight() { + const auto& ridx = get_index_type().indices().get(); + for( const auto& i : ridx ) { + modify( i, []( liquidity_reward_balance_object& o ){ + o.update_weight(true/*HAS HARDFORK9 if this method is called*/); + }); + } +} + /** * Verifies all supply invariantes check out */ diff --git a/libraries/chain/hardfork.d/0-preamble.hf b/libraries/chain/hardfork.d/0-preamble.hf index ed09953202..17d28491c5 100644 --- a/libraries/chain/hardfork.d/0-preamble.hf +++ b/libraries/chain/hardfork.d/0-preamble.hf @@ -33,5 +33,5 @@ FC_REFLECT_DERIVED( steemit::chain::hardfork_property_object, (graphene::db::obj (processed_hardforks)(last_hardfork)(current_hardfork_version) (next_hardfork)(next_hardfork_time) ) -#define STEEMIT_NUM_HARDFORKS 8 +#define STEEMIT_NUM_HARDFORKS 9 diff --git a/libraries/chain/hardfork.d/0_9.hf b/libraries/chain/hardfork.d/0_9.hf new file mode 100644 index 0000000000..0796c102fa --- /dev/null +++ b/libraries/chain/hardfork.d/0_9.hf @@ -0,0 +1,303 @@ +#ifndef STEEMIT_HARDFORK_0_9 +#define STEEMIT_HARDFORK_0_9 9 +#define STEEMIT_HARDFORK_0_9__141 STEEMIT_HARDFORK_0_9 +#define STEEMIT_HARDFORK_0_9__147 STEEMIT_HARDFORK_0_9 +#define STEEMIT_HARDFORK_0_9__149 STEEMIT_HARDFORK_0_9 + +#define STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9 fc::seconds(60*30) /// 30 min +#define STEEMIT_HARDFORK_0_9_TIME 1468454400 // 2016-07-14T00:00:00 UTC +#define STEEMIT_HARDFORK_0_9_VERSION hardfork_version( 0, 9 ) + +namespace hardfork9 +{ + +inline static const std::set< std::string >& get_compromised_accounts() +{ + static const std::set< std::string > compromised_accounts + { + "addicted", + "adrehajiuh", + "aeico", + "afrizalaf", + "aizensou", + "alejandradd", + "alexbulkin", + "alyssas", + "amartinezque", + "amgosser", + "anamichii", + "anatoliy", + "andrevarela", + "andysandors", + "animalrobot", + "apollosantana", + "arwani-wawan", + "ashleycolum", + "auxon", + "avenireduc", + "awesome", + "baltas", + "berkut", + "bigpappa", + "binwah-de-rese", + "blackjincrypto", + "blueorgy", + "boatymcboatface", + "bobdownlov", + "boris-agatic", + "brandon-hills", + "bravenewcoin", + "breakfastchief", + "btcturbo", + "budi-bayu", + "bunny", + "burgalu", + "canltu", + "cavaleries", + "chamviet", + "chessmonster", + "chhayll", + "chillipepper", + "chitty", + "chryspano", + "cleiton", + "cliro", + "cmtzco", + "coinbitgold", + "coinfund", + "cryptodao", + "cryptodon", + "dahaz159", + "dan", + "dantheman", + "darkob", + "darkstormrise", + "dashtipbot", + "davidgriffin", + "daycrypter", + "dea", + "dea-anjas-fahma", + "dev00100000", + "discovery", + "dmitriybtc", + "dollyllama", + "drone-85426", + "drone28", + "dudutaulois", + "dulila", + "durandal", + "elyaque", + "erq", + "estin", + "ethbull", + "expanse", + "facer", + "fanie-vanhoten", + "febuiles", + "felipemachado", + "fex", + "filippo", + "fishayley", + "fzeoli", + "gabbans", + "ganksta444", + "gatoso", + "gazm", + "gbert", + "geezee", + "ginolino", + "goodgame", + "gottahaveit", + "gregm", + "griffitsj", + "grxcii", + "happytorn", + "hcf27", + "hipster", + "hostfat", + "ian.ridgwell", + "ibnu", + "icaro", + "ihashfury", + "j4se", + "jacor", + "james1337", + "jarnostoter", + "jearson", + "jeffersontavares", + "jehova", + "jhirsch41", + "john-kimmel", + "johsin28", + "jokerdarkknight", + "jonhuang", + "josiahredding", + "justiciar", + "kaj-huisman", + "kaptainkrayola", + "karama", + "karen13", + "karengigi", + "kedhit", + "kekoacoaching", + "kevin-colussi", + "kevinwong", + "kingofchaos", + "klander", + "knoopx", + "kufan", + "leksimus", + "libdep", + "linda-gilner", + "loewan", + "lrock", + "luiz-marchi", + "lux", + "madhanmogan", + "magz8716", + "marcelhattingh", + "mathiasbaer", + "matthiaspolet", + "mauricemikkers", + "meesterboom", + "megabucks", + "melbinvarghese", + "mephdxa21", + "mexbit", + "mikevas", + "minergate123", + "mldorton", + "mrfeilong", + "msutyler", + "mynameisbrian", + "necha", + "ned", + "ned-scott", + "nguyenthanhlong", + "nicku", + "nicolaswsk", + "nin0000", + "norbu", + "normalpha", + "novarro", + "nuno-nutcrusherz", + "omarb", + "omarbitcoin", + "orenmor", + "owdy", + "ozmaster", + "ozzy-vega", + "pal", + "paulsimons", + "peezaroni", + "philopseudes", + "pierregi", + "pieter", + "poneb", + "przeor", + "pwlaslo", + "qamarpinkpanda", + "qwear", + "qwertas", + "rail", + "ram", + "recursive", + "ridz84", + "rimantas", + "rok-sivante", + "rosetower", + "rseixas", + "rytu", + "samupaha", + "scar", + "schro", + "sebastien", + "sebhaj", + "setme", + "sevich", + "sexyama", + "simoneighties", + "sinraf96", + "sitaru", + "skreets", + "slava", + "slocum", + "snake", + "soggypotatos", + "solomon-adekale", + "sonzweil", + "sophiaveritas", + "spartako", + "stabilnotixo", + "stan", + "stangrotic", + "steemit1", + "steemitblog", + "steempower", + "steemtest", + "steg", + "stompy", + "str11ngfello", + "streetstyle", + "tals", + "techemist", + "teddy-greget", + "texastiger", + "the-alien", + "thecryptodrive", + "thegoodguy", + "thenerdydeviant", + "thismayor", + "thmdias", + "timer-the-teemer", + "toknormal", + "tommyarnold", + "tonykent", + "top10", + "trevonjb", + "troller", + "trung81", + "ttt3", + "tyronne", + "ukon", + "val", + "victor-scott", + "vilivolcini", + "vippero", + "wanted22", + "willidungl", + "windsok", + "wingz", + "worldfamous", + "wrightlabs", + "xema2110", + "yan-kovalenko", + "yayahuaist", + "ye11ow", + "zebbra2014", + "zelgald1", + "zer0sum" + }; + + return compromised_accounts; +} + +inline static const std::set< std::string >& get_bad_memos() +{ + static const std::set< std::string > bad_memos + { + "5cd80b47e6764534b0f", + "c5149362bb7842cea10", + "b056089187754e71b32", + "e01abe56614548d48cc", + "294354b63c0c4d4dadb", + "96978449f7ca4ea48d1", + "28cbdfb353414d548fe", + "2f5b42d7408c43fc986" + }; + + return bad_memos; +} + +} +#endif diff --git a/libraries/chain/include/steemit/chain/account_object.hpp b/libraries/chain/include/steemit/chain/account_object.hpp index 6ccc62c1f0..17fef4d766 100644 --- a/libraries/chain/include/steemit/chain/account_object.hpp +++ b/libraries/chain/include/steemit/chain/account_object.hpp @@ -27,6 +27,8 @@ namespace steemit { namespace chain { string json_metadata = ""; string proxy; + time_point_sec last_owner_update; + time_point_sec created; bool mined = true; uint32_t comment_count = 0; @@ -147,6 +149,7 @@ namespace steemit { namespace chain { struct by_smd_balance; struct by_post_count; struct by_vote_count; + struct by_last_owner_update; /** * @ingroup object_index @@ -211,6 +214,13 @@ namespace steemit { namespace chain { member >, composite_key_compare< std::greater< uint32_t >, std::less< object_id_type > > + >, + ordered_unique< tag< by_last_owner_update >, + composite_key< account_object, + member, + member + >, + composite_key_compare< std::greater< time_point_sec >, std::less< object_id_type > > > > > account_multi_index_type; @@ -220,7 +230,7 @@ namespace steemit { namespace chain { } } FC_REFLECT_DERIVED( steemit::chain::account_object, (graphene::db::object), - (name)(owner)(active)(posting)(memo_key)(json_metadata)(proxy) + (name)(owner)(active)(posting)(memo_key)(json_metadata)(proxy)(last_owner_update) (created)(mined)(comment_count)(lifetime_vote_count)(post_count)(voting_power)(last_vote_time) (balance) (sbd_balance)(sbd_seconds)(sbd_seconds_last_update)(sbd_last_interest_payment) diff --git a/libraries/chain/include/steemit/chain/comment_object.hpp b/libraries/chain/include/steemit/chain/comment_object.hpp index 7cf273796a..1d0e92a3f5 100644 --- a/libraries/chain/include/steemit/chain/comment_object.hpp +++ b/libraries/chain/include/steemit/chain/comment_object.hpp @@ -106,6 +106,7 @@ namespace steemit { namespace chain { /** tracks the total payout this comment has received over time, measured in SBD */ asset total_payout_value = asset(0, SBD_SYMBOL); + asset curator_payout_value = asset(0, SBD_SYMBOL); share_type author_rewards = 0; @@ -336,7 +337,7 @@ FC_REFLECT_DERIVED( steemit::chain::comment_object, (graphene::db::object), (depth)(children)(children_rshares2) (net_rshares)(abs_rshares)(vote_rshares) (children_abs_rshares)(cashout_time)(max_cashout_time) - (total_vote_weight)(total_payout_value)(author_rewards)(net_votes)(root_comment) + (total_vote_weight)(total_payout_value)(curator_payout_value)(author_rewards)(net_votes)(root_comment) (max_accepted_payout)(percent_steem_dollars)(allow_replies)(allow_votes)(allow_curation_rewards) ) FC_REFLECT_DERIVED( steemit::chain::comment_vote_object, (graphene::db::object), diff --git a/libraries/chain/include/steemit/chain/config.hpp b/libraries/chain/include/steemit/chain/config.hpp index c23b98e228..30b0a91d4c 100644 --- a/libraries/chain/include/steemit/chain/config.hpp +++ b/libraries/chain/include/steemit/chain/config.hpp @@ -3,7 +3,7 @@ */ #pragma once -#define STEEMIT_BLOCKCHAIN_VERSION ( version(0, 8, 5) ) +#define STEEMIT_BLOCKCHAIN_VERSION ( version(0, 9, 0) ) #define STEEMIT_BLOCKCHAIN_HARDFORK_VERSION ( hardfork_version( STEEMIT_BLOCKCHAIN_VERSION ) ) #ifdef IS_TEST_NET diff --git a/libraries/chain/include/steemit/chain/database.hpp b/libraries/chain/include/steemit/chain/database.hpp index 708b935dd8..c887e8ddfd 100644 --- a/libraries/chain/include/steemit/chain/database.hpp +++ b/libraries/chain/include/steemit/chain/database.hpp @@ -105,6 +105,7 @@ namespace steemit { namespace chain { const witness_object& get_witness( const string& name )const; const account_object& get_account( const string& name )const; const comment_object& get_comment( const string& author, const string& permlink )const; + const escrow_object& get_escrow( const string& name, uint32_t escrowid )const; const time_point_sec calculate_discussion_payout_time( const comment_object& comment )const; const limit_order_object& get_limit_order( const string& owner, uint32_t id )const; const limit_order_object* find_limit_order( const string& owner, uint32_t id )const; @@ -161,13 +162,6 @@ namespace steemit { namespace chain { void push_applied_operation( const operation& op ); void notify_post_apply_operation( const operation& op ); - /** - * This signal is emitted for plugins to process every operation before it gets applied. - * - * @deprecated - use pre_apply_operation instead - */ - fc::signal on_applied_operation; - /** * This signal is emitted for plugins to process every operation after it has been fully applied. */ @@ -243,7 +237,7 @@ namespace steemit { namespace chain { asset create_sbd( const account_object& to_account, asset steem ); asset create_vesting( const account_object& to_account, asset steem ); void update_account_activity( const account_object& account ); - void adjust_total_payout( const comment_object& a, const asset& sbd ); + void adjust_total_payout( const comment_object& a, const asset& sbd, const asset& curator_sbd_value ); void update_witness_schedule(); @@ -356,6 +350,7 @@ namespace steemit { namespace chain { void retally_comment_children(); void retally_witness_votes(); void retally_witness_vote_counts( bool force = false ); + void retally_liquidity_weight(); bool has_hardfork( uint32_t hardfork )const; @@ -367,6 +362,11 @@ namespace steemit { namespace chain { /** * @} */ + +#ifdef IS_TEST_NET + bool liquidity_rewards_enabled = true; +#endif + protected: //Mark pop_undo() as protected -- we do not want outside calling pop_undo(); it should call pop_block() instead void pop_undo() { object_database::pop_undo(); } diff --git a/libraries/chain/include/steemit/chain/global_property_object.hpp b/libraries/chain/include/steemit/chain/global_property_object.hpp index 7c48135634..346625ee3b 100644 --- a/libraries/chain/include/steemit/chain/global_property_object.hpp +++ b/libraries/chain/include/steemit/chain/global_property_object.hpp @@ -52,12 +52,12 @@ namespace steemit { namespace chain { /** * These fields are used to reward users who remain active. Every block 15% of - * content + curation rewards steem is placed into the activity fund steem. + * content + curation rewards steem is placed into the activity fund steem. * * Every time a user votes they earn activity_fund_shares which are calculated as * min(time_since_last_active,24h) * VESTS. This is designed to reward those who * check in daily. Activity rewards can only be earned by accounts with trival - * posting authorities consisting of a single key. + * posting authorities consisting of a single key. */ //@{ asset total_activity_fund_steem = asset( 0, STEEM_SYMBOL ); @@ -108,6 +108,7 @@ namespace steemit { namespace chain { * used to compute witness participation. */ fc::uint128_t recent_slots_filled; + uint8_t participation_count; ///< Divide by 128 to compute participation percentage uint32_t last_irreversible_block_num = 0; @@ -155,6 +156,7 @@ FC_REFLECT_DERIVED( steemit::chain::dynamic_global_property_object, (graphene::d (maximum_block_size) (current_aslot) (recent_slots_filled) + (participation_count) (last_irreversible_block_num) (max_virtual_bandwidth) (current_reserve_ratio) diff --git a/libraries/chain/include/steemit/chain/protocol/operations.hpp b/libraries/chain/include/steemit/chain/protocol/operations.hpp index 33709ea10c..c5b9cb1f11 100644 --- a/libraries/chain/include/steemit/chain/protocol/operations.hpp +++ b/libraries/chain/include/steemit/chain/protocol/operations.hpp @@ -38,6 +38,10 @@ namespace steemit { namespace chain { custom_json_operation, comment_options_operation, set_withdraw_vesting_route_operation, + limit_order_create2_operation, + escrow_transfer_operation, + escrow_dispute_operation, + escrow_release_operation, /// virtual operations below this point fill_convert_request_operation, diff --git a/libraries/chain/include/steemit/chain/protocol/sign_state.hpp b/libraries/chain/include/steemit/chain/protocol/sign_state.hpp new file mode 100644 index 0000000000..b3d923c710 --- /dev/null +++ b/libraries/chain/include/steemit/chain/protocol/sign_state.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +namespace steemit { namespace chain { + +typedef std::function authority_getter; + +struct sign_state +{ + /** returns true if we have a signature for this key or can + * produce a signature for this key, else returns false. + */ + bool signed_by( const public_key_type& k ); + bool check_authority( string id ); + + /** + * Checks to see if we have signatures of the active authorites of + * the accounts specified in authority or the keys specified. + */ + bool check_authority( const authority* au, uint32_t depth = 0 ); + + bool remove_unused_signatures(); + + sign_state( const flat_set& sigs, + const authority_getter& a, + const flat_set& keys = flat_set() ); + + const authority_getter& get_active; + const flat_set& available_keys; + + flat_map provided_signatures; + flat_set approved_by; + uint32_t max_recursion = STEEMIT_MAX_SIG_CHECK_DEPTH; +}; + +} } diff --git a/libraries/chain/include/steemit/chain/protocol/steem_operations.hpp b/libraries/chain/include/steemit/chain/protocol/steem_operations.hpp index 71af10cb82..6baf13b199 100644 --- a/libraries/chain/include/steemit/chain/protocol/steem_operations.hpp +++ b/libraries/chain/include/steemit/chain/protocol/steem_operations.hpp @@ -203,6 +203,65 @@ namespace steemit { namespace chain { void get_required_owner_authorities( flat_set& a )const { if(amount.symbol == VESTS_SYMBOL) a.insert(from); } }; + /** + * The purpose of this operation is to enable someone to send money contingently to + * another individual. The funds leave the *from* account and go into a temporary balance + * where they are held until *from* releases it to *to* or *to* refunds it to *from*. + * + * In the event of a dispute the *agent* can divide the funds between the to/from account. + * + * The escrow agent is paid the fee no matter what. It is up to the escrow agent to determine + * + * Escrow transactions are uniquely identified by 'from' and 'escrow_id', the 'escrow_id' is defined + * by the sender. + */ + struct escrow_transfer_operation : public base_operation { + string from; + string to; + asset amount; + string memo; + + uint32_t escrow_id; + string agent; + asset fee; + string json_meta; + time_point_sec expiration; + + void validate()const; + void get_required_active_authorities( flat_set& a )const{ a.insert(from); } + }; + + /** + * If either the sender or receiver of an escrow payment has an issue, they can + * raise it for dispute. Once a payment is in dispute, the agent has authority over + * who gets what. + */ + struct escrow_dispute_operation : public base_operation { + string from; + string to; + uint32_t escrow_id; + string who; + + void validate()const; + void get_required_active_authorities( flat_set& a )const{ a.insert(who); } + }; + + /** + * This operation can be used by anyone associated with the escrow transfer to + * release funds if they have permission. + */ + struct escrow_release_operation : public base_operation { + string from; + uint32_t escrow_id; + string to; ///< the account that should receive funds (might be from, might be to + string who; ///< the account that is attempting to release the funds, determines valid 'to' + asset amount; ///< the amount of funds to release + + void validate()const; + void get_required_active_authorities( flat_set& a )const{ a.insert(who); } + }; + + /** * This operation converts STEEM into VFS (Vesting Fund Shares) at * the current exchange rate. With this operation it is possible to @@ -420,6 +479,32 @@ namespace steemit { namespace chain { } }; + /** + * This operation is identical to limit_order_create except it serializes the price rather + * than calculating it from other fields. + */ + struct limit_order_create2_operation : public base_operation + { + string owner; + uint32_t orderid = 0; /// an ID assigned by owner, must be unique + asset amount_to_sell; + bool fill_or_kill = false; + price exchange_rate; + time_point_sec expiration = time_point_sec::maximum(); + + void validate()const; + void get_required_active_authorities( flat_set& a )const{ a.insert(owner); } + + price get_price()const { return exchange_rate; } + + pair get_market()const + { + return exchange_rate.base.symbol < exchange_rate.quote.symbol ? + std::make_pair(exchange_rate.base.symbol, exchange_rate.quote.symbol) : + std::make_pair(exchange_rate.quote.symbol, exchange_rate.base.symbol); + } + }; + struct fill_order_operation : public base_operation { fill_order_operation(){} fill_order_operation( const string& c_o, uint32_t c_id, const asset& c_p, const string& o_o, uint32_t o_id, const asset& o_p ) @@ -531,6 +616,7 @@ FC_REFLECT( steemit::chain::vote_operation, (voter)(author)(permlink)(weight) ) FC_REFLECT( steemit::chain::custom_operation, (required_auths)(id)(data) ) FC_REFLECT( steemit::chain::custom_json_operation, (required_auths)(required_posting_auths)(id)(json) ) FC_REFLECT( steemit::chain::limit_order_create_operation, (owner)(orderid)(amount_to_sell)(min_to_receive)(fill_or_kill)(expiration) ) +FC_REFLECT( steemit::chain::limit_order_create2_operation, (owner)(orderid)(amount_to_sell)(exchange_rate)(fill_or_kill)(expiration) ) FC_REFLECT( steemit::chain::fill_order_operation, (current_owner)(current_orderid)(current_pays)(open_owner)(open_orderid)(open_pays) ); FC_REFLECT( steemit::chain::limit_order_cancel_operation, (owner)(orderid) ) @@ -544,4 +630,8 @@ FC_REFLECT( steemit::chain::fill_vesting_withdraw_operation, (from_account)(to_a FC_REFLECT( steemit::chain::delete_comment_operation, (author)(permlink) ); FC_REFLECT( steemit::chain::comment_options_operation, (author)(permlink)(max_accepted_payout)(percent_steem_dollars)(allow_votes)(allow_curation_rewards)(extensions) ) -FC_REFLECT_TYPENAME( steemit::chain::comment_options ) \ No newline at end of file +FC_REFLECT( steemit::chain::escrow_transfer_operation, (from)(to)(amount)(memo)(escrow_id)(agent)(fee)(json_meta)(expiration) ); +FC_REFLECT( steemit::chain::escrow_dispute_operation, (from)(to)(escrow_id)(who) ); +FC_REFLECT( steemit::chain::escrow_release_operation, (from)(to)(escrow_id)(who)(amount) ); + +FC_REFLECT_TYPENAME( steemit::chain::comment_options ) diff --git a/libraries/chain/include/steemit/chain/protocol/transaction.hpp b/libraries/chain/include/steemit/chain/protocol/transaction.hpp index e61e02cb11..a27aab9afe 100644 --- a/libraries/chain/include/steemit/chain/protocol/transaction.hpp +++ b/libraries/chain/include/steemit/chain/protocol/transaction.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -47,8 +48,6 @@ namespace steemit { namespace chain { vector& other )const; }; - typedef std::function authority_getter; - struct signed_transaction : public transaction { signed_transaction( const transaction& trx = transaction() ) diff --git a/libraries/chain/include/steemit/chain/protocol/types.hpp b/libraries/chain/include/steemit/chain/protocol/types.hpp index df8c94badd..8bf41b4c6a 100644 --- a/libraries/chain/include/steemit/chain/protocol/types.hpp +++ b/libraries/chain/include/steemit/chain/protocol/types.hpp @@ -114,7 +114,8 @@ namespace steemit { namespace chain { impl_account_history_object_type, impl_category_object_type, impl_hardfork_property_object_type, - impl_withdraw_vesting_route_object_type + impl_withdraw_vesting_route_object_type, + impl_escrow_object_type }; class operation_object; @@ -139,6 +140,7 @@ namespace steemit { namespace chain { class liquidity_reward_balance_object; class hardfork_property_object; class withdraw_vesting_route_object; + class escrow_object; typedef object_id< implementation_ids, impl_operation_object_type, operation_object > operation_id_type; typedef object_id< implementation_ids, impl_account_history_object_type, account_history_object > account_history_id_type; @@ -161,6 +163,7 @@ namespace steemit { namespace chain { typedef object_id< implementation_ids, impl_liquidity_reward_balance_object_type, liquidity_reward_balance_object > liquidity_reward_balance_id_type; typedef object_id< implementation_ids, impl_hardfork_property_object_type, hardfork_property_object > hardfork_property_id_type; typedef object_id< implementation_ids, impl_withdraw_vesting_route_object_type, withdraw_vesting_route_object > withdraw_vesting_route_id_type; + typedef object_id< implementation_ids, impl_escrow_object_type, escrow_object > escrow_id_type; typedef fc::ripemd160 block_id_type; typedef fc::ripemd160 checksum_type; @@ -285,6 +288,7 @@ FC_REFLECT_ENUM( steemit::chain::impl_object_type, (impl_account_history_object_type) (impl_hardfork_property_object_type) (impl_withdraw_vesting_route_object_type) + (impl_escrow_object_type) ) FC_REFLECT_TYPENAME( steemit::chain::share_type ) diff --git a/libraries/chain/include/steemit/chain/steem_evaluator.hpp b/libraries/chain/include/steemit/chain/steem_evaluator.hpp index 1a52c33875..4db87b57be 100644 --- a/libraries/chain/include/steemit/chain/steem_evaluator.hpp +++ b/libraries/chain/include/steemit/chain/steem_evaluator.hpp @@ -32,5 +32,9 @@ DEFINE_EVALUATOR( convert ) DEFINE_EVALUATOR( limit_order_create ) DEFINE_EVALUATOR( limit_order_cancel ) DEFINE_EVALUATOR( report_over_production ) +DEFINE_EVALUATOR( limit_order_create2 ) +DEFINE_EVALUATOR( escrow_transfer ) +DEFINE_EVALUATOR( escrow_dispute ) +DEFINE_EVALUATOR( escrow_release ) } } // steemit::chain diff --git a/libraries/chain/include/steemit/chain/steem_objects.hpp b/libraries/chain/include/steemit/chain/steem_objects.hpp index 47feeb36b9..505ba88f5a 100755 --- a/libraries/chain/include/steemit/chain/steem_objects.hpp +++ b/libraries/chain/include/steemit/chain/steem_objects.hpp @@ -29,6 +29,21 @@ namespace steemit { namespace chain { time_point_sec conversion_date; ///< at this time the feed_history_median_price * amount }; + class escrow_object : public abstract_object { + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_escrow_object_type; + + uint32_t escrow_id; + string from; + string to; + string agent; + time_point_sec expiration; + asset balance; + bool disputed = false; + }; + + /** * If last_update is greater than 1 week, then volume gets reset to 0 @@ -49,9 +64,18 @@ namespace steemit { namespace chain { account_id_type owner; int64_t steem_volume = 0; int64_t sbd_volume = 0; + uint128_t weight = 0; /// this is the sort index - uint128_t volume_weight()const { return steem_volume * sbd_volume * is_positive(); } + uint128_t volume_weight()const { + return steem_volume * sbd_volume * is_positive(); + } + uint128_t min_volume_weight()const { + return std::min(steem_volume,sbd_volume) * is_positive(); + } + void update_weight( bool hf9 ) { + weight = hf9 ? min_volume_weight() : volume_weight(); + } inline int is_positive()const { return ( steem_volume > 0 && sbd_volume > 0 ) ? 1 : 0; } @@ -172,7 +196,7 @@ namespace steemit { namespace chain { ordered_unique< tag< by_owner >, member< liquidity_reward_balance_object, account_id_type, &liquidity_reward_balance_object::owner > >, ordered_unique< tag< by_volume_weight >, composite_key< liquidity_reward_balance_object, - const_mem_fun< liquidity_reward_balance_object, fc::uint128, &liquidity_reward_balance_object::volume_weight >, + member< liquidity_reward_balance_object, fc::uint128, &liquidity_reward_balance_object::weight >, member< liquidity_reward_balance_object, account_id_type, &liquidity_reward_balance_object::owner > >, composite_key_compare< std::greater, std::less< account_id_type > > @@ -195,6 +219,34 @@ namespace steemit { namespace chain { > > withdraw_vesting_route_index_type; + struct by_from_id; + struct by_to; + struct by_agent; + typedef multi_index_container< + escrow_object, + indexed_by< + ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >, + ordered_unique< tag< by_from_id >, + composite_key< escrow_object, + member< escrow_object, string, &escrow_object::from >, + member< escrow_object, uint32_t, &escrow_object::escrow_id > + > + >, + ordered_unique< tag< by_to >, + composite_key< escrow_object, + member< escrow_object, string, &escrow_object::to >, + member< object, object_id_type, &object::id > + > + >, + ordered_unique< tag< by_agent >, + composite_key< escrow_object, + member< escrow_object, string, &escrow_object::agent >, + member< object, object_id_type, &object::id > + > + > + > + > escrow_object_index_type; + /** * @ingroup object_index */ @@ -202,6 +254,7 @@ namespace steemit { namespace chain { typedef generic_index< limit_order_object, limit_order_multi_index_type > limit_order_index; typedef generic_index< liquidity_reward_balance_object, liquidity_reward_balance_index_type > liquidity_reward_index; typedef generic_index< withdraw_vesting_route_object, withdraw_vesting_route_index_type > withdraw_vesting_route_index; + typedef generic_index< escrow_object, escrow_object_index_type > escrow_index; } } // steemit::chain @@ -219,7 +272,10 @@ FC_REFLECT_DERIVED( steemit::chain::convert_request_object, (graphene::db::objec (owner)(requestid)(amount)(conversion_date) ) FC_REFLECT_DERIVED( steemit::chain::liquidity_reward_balance_object, (graphene::db::object), - (owner)(steem_volume)(sbd_volume)(last_update) ) + (owner)(steem_volume)(sbd_volume)(weight)(last_update) ) FC_REFLECT_DERIVED( steemit::chain::withdraw_vesting_route_object, (graphene::db::object), (from_account)(to_account)(percent)(auto_vest) ) + +FC_REFLECT_DERIVED( steemit::chain::escrow_object, (graphene::db::object), + (escrow_id)(from)(to)(agent)(expiration)(balance)(disputed) ); diff --git a/libraries/chain/protocol/sign_state.cpp b/libraries/chain/protocol/sign_state.cpp new file mode 100644 index 0000000000..641fc4a332 --- /dev/null +++ b/libraries/chain/protocol/sign_state.cpp @@ -0,0 +1,87 @@ + +#include + +namespace steemit { namespace chain { + +bool sign_state::signed_by( const public_key_type& k ) +{ + auto itr = provided_signatures.find(k); + if( itr == provided_signatures.end() ) + { + auto pk = available_keys.find(k); + if( pk != available_keys.end() ) + return provided_signatures[k] = true; + return false; + } + return itr->second = true; +} + +bool sign_state::check_authority( string id ) +{ + if( approved_by.find(id) != approved_by.end() ) return true; + return check_authority( get_active(id) ); +} + +bool sign_state::check_authority( const authority* au, uint32_t depth ) +{ + if( au == nullptr ) return false; + const authority& auth = *au; + + uint32_t total_weight = 0; + for( const auto& k : auth.key_auths ) + if( signed_by( k.first ) ) + { + total_weight += k.second; + if( total_weight >= auth.weight_threshold ) + return true; + } + + + for( const auto& a : auth.account_auths ) + { + if( approved_by.find(a.first) == approved_by.end() ) + { + if( depth == max_recursion ) + continue; + if( check_authority( get_active( a.first ), depth+1 ) ) + { + approved_by.insert( a.first ); + total_weight += a.second; + if( total_weight >= auth.weight_threshold ) + return true; + } + } + else + { + total_weight += a.second; + if( total_weight >= auth.weight_threshold ) + return true; + } + } + return total_weight >= auth.weight_threshold; +} + +bool sign_state::remove_unused_signatures() +{ + vector remove_sigs; + for( const auto& sig : provided_signatures ) + if( !sig.second ) remove_sigs.push_back( sig.first ); + + for( auto& sig : remove_sigs ) + provided_signatures.erase(sig); + + return remove_sigs.size() != 0; +} + +sign_state::sign_state( + const flat_set& sigs, + const authority_getter& a, + const flat_set& keys + ) : get_active(a), available_keys(keys) +{ + for( const auto& key : sigs ) + provided_signatures[ key ] = false; + approved_by.insert( "temp" ); +} + +} } // steemit::chain diff --git a/libraries/chain/protocol/steem_operations.cpp b/libraries/chain/protocol/steem_operations.cpp index 185e3aeb28..f01104f9fa 100644 --- a/libraries/chain/protocol/steem_operations.cpp +++ b/libraries/chain/protocol/steem_operations.cpp @@ -204,6 +204,16 @@ namespace steemit { namespace chain { || ( is_asset_type( amount_to_sell, SBD_SYMBOL ) && is_asset_type( min_to_receive, STEEM_SYMBOL ) ) ); (amount_to_sell / min_to_receive).validate(); } + void limit_order_create2_operation::validate()const { + FC_ASSERT( is_valid_account_name( owner ) ); + FC_ASSERT( amount_to_sell.symbol == exchange_rate.base.symbol ); + exchange_rate.validate(); + + FC_ASSERT( ( is_asset_type( amount_to_sell, STEEM_SYMBOL ) && is_asset_type( exchange_rate.quote, SBD_SYMBOL ) ) || + ( is_asset_type( amount_to_sell, SBD_SYMBOL ) && is_asset_type( exchange_rate.quote, STEEM_SYMBOL ) ) ); + + FC_ASSERT( (amount_to_sell * exchange_rate).amount > 0 ); // must not round to 0 + } void limit_order_cancel_operation::validate()const { @@ -227,5 +237,29 @@ namespace steemit { namespace chain { FC_ASSERT( first_block.id() != second_block.id() ); } + void escrow_transfer_operation::validate()const { + FC_ASSERT( is_valid_account_name( from ) ); + FC_ASSERT( is_valid_account_name( to ) ); + FC_ASSERT( is_valid_account_name( agent ) ); + FC_ASSERT( fee.amount >= 0 ); + FC_ASSERT( amount.amount >= 0 ); + FC_ASSERT( from != agent && to != agent ); + FC_ASSERT( fee.symbol == amount.symbol ); + FC_ASSERT( amount.symbol != VESTS_SYMBOL ); + } + void escrow_dispute_operation::validate()const { + FC_ASSERT( is_valid_account_name( from ) ); + FC_ASSERT( is_valid_account_name( to ) ); + FC_ASSERT( is_valid_account_name( who ) ); + FC_ASSERT( who == from || who == to ); + } + void escrow_release_operation::validate()const { + FC_ASSERT( is_valid_account_name( from ) ); + FC_ASSERT( is_valid_account_name( to ) ); + FC_ASSERT( is_valid_account_name( who ) ); + FC_ASSERT( amount.amount > 0 ); + FC_ASSERT( amount.symbol != VESTS_SYMBOL ); + } + } } // steemit::chain diff --git a/libraries/chain/protocol/transaction.cpp b/libraries/chain/protocol/transaction.cpp index 2fb9d6637e..c2019ebaf1 100644 --- a/libraries/chain/protocol/transaction.cpp +++ b/libraries/chain/protocol/transaction.cpp @@ -1,7 +1,12 @@ + +#include + #include + #include #include #include + #include namespace steemit { namespace chain { @@ -80,107 +85,6 @@ void transaction::get_required_authorities( flat_set& active, operation_get_required_authorities( op, active, owner, posting, other ); } - - - -struct sign_state -{ - /** returns true if we have a signature for this key or can - * produce a signature for this key, else returns false. - */ - bool signed_by( const public_key_type& k ) - { - auto itr = provided_signatures.find(k); - if( itr == provided_signatures.end() ) - { - auto pk = available_keys.find(k); - if( pk != available_keys.end() ) - return provided_signatures[k] = true; - return false; - } - return itr->second = true; - } - - bool check_authority( string id ) - { - if( approved_by.find(id) != approved_by.end() ) return true; - return check_authority( get_active(id) ); - } - - /** - * Checks to see if we have signatures of the active authorites of - * the accounts specified in authority or the keys specified. - */ - bool check_authority( const authority* au, uint32_t depth = 0 ) - { - if( au == nullptr ) return false; - const authority& auth = *au; - - uint32_t total_weight = 0; - for( const auto& k : auth.key_auths ) - if( signed_by( k.first ) ) - { - total_weight += k.second; - if( total_weight >= auth.weight_threshold ) - return true; - } - - - for( const auto& a : auth.account_auths ) - { - if( approved_by.find(a.first) == approved_by.end() ) - { - if( depth == max_recursion ) - continue; - if( check_authority( get_active( a.first ), depth+1 ) ) - { - approved_by.insert( a.first ); - total_weight += a.second; - if( total_weight >= auth.weight_threshold ) - return true; - } - } - else - { - total_weight += a.second; - if( total_weight >= auth.weight_threshold ) - return true; - } - } - return total_weight >= auth.weight_threshold; - } - - bool remove_unused_signatures() - { - vector remove_sigs; - for( const auto& sig : provided_signatures ) - if( !sig.second ) remove_sigs.push_back( sig.first ); - - for( auto& sig : remove_sigs ) - provided_signatures.erase(sig); - - return remove_sigs.size() != 0; - } - - sign_state( const flat_set& sigs, - const authority_getter& a, - const flat_set& keys = flat_set() ) - :get_active(a),available_keys(keys) - { - for( const auto& key : sigs ) - provided_signatures[ key ] = false; - approved_by.insert( "temp" ); - } - - const authority_getter& get_active; - const flat_set& available_keys; - - flat_map provided_signatures; - flat_set approved_by; - uint32_t max_recursion = STEEMIT_MAX_SIG_CHECK_DEPTH; -}; - - void verify_authority( const vector& ops, const flat_set& sigs, const authority_getter& get_active, const authority_getter& get_owner, diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index ee62db64a9..867f883fe0 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -104,6 +104,7 @@ void account_create_evaluator::do_apply( const account_create_operation& o ) acc.active = o.active; acc.posting = o.posting; acc.memo_key = o.memo_key; + acc.last_owner_update = props.time; acc.created = props.time; acc.last_vote_time = props.time; acc.mined = false; @@ -124,7 +125,11 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) db().modify( db().get_account( o.account ), [&]( account_object& acc ) { - if( o.owner ) acc.owner = *o.owner; + if( o.owner ) + { + acc.owner = *o.owner; + acc.last_owner_update = db().head_block_time(); + } if( o.active ) acc.active = *o.active; if( o.posting ) acc.posting = *o.posting; @@ -136,6 +141,7 @@ void account_update_evaluator::do_apply( const account_update_operation& o ) acc.json_metadata = o.json_metadata; #endif }); + } @@ -182,6 +188,14 @@ void delete_comment_evaluator::do_apply( const delete_comment_operation& o ) { } } + /** TODO move category behavior to a plugin, this is not part of consensus */ + const category_object* cat = db().find_category( comment.category ); + db().modify( *cat, [&]( category_object& c ) + { + c.discussions--; + c.last_update = db().head_block_time(); + }); + db().remove( comment ); } @@ -373,6 +387,83 @@ void comment_evaluator::do_apply( const comment_operation& o ) } FC_CAPTURE_AND_RETHROW( (o) ) } +void escrow_transfer_evaluator::do_apply( const escrow_transfer_operation& o ) { +try { + FC_ASSERT( false, "Escrow transfer operation not enabled" ); + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_0_9 ) ); /// TODO: remove this after HF9 + + const auto& from_account = db().get_account(o.from); + db().get_account(o.to); + const auto& agent_account = db().get_account(o.agent); + + FC_ASSERT( db().get_balance( from_account, o.amount.symbol ) >= (o.amount + o.fee) ); + + if( o.fee.amount > 0 ) { + db().adjust_balance( from_account, -o.fee ); + db().adjust_balance( agent_account, o.fee ); + } + + db().adjust_balance( from_account, -o.amount ); + + db().create([&]( escrow_object& esc ) { + esc.escrow_id = o.escrow_id; + esc.from = o.from; + esc.to = o.to; + esc.agent = o.agent; + esc.balance = o.amount; + esc.expiration = o.expiration; + }); + +} FC_CAPTURE_AND_RETHROW( (o) ) } + +void escrow_dispute_evaluator::do_apply( const escrow_dispute_operation& o ) { +try { + FC_ASSERT( false, "Escrow dispute operation not enabled" ); + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_0_9 ) ); /// TODO: remove this after HF9 + const auto& from_account = db().get_account(o.from); + + const auto& e = db().get_escrow( o.from, o.escrow_id ); + FC_ASSERT( !e.disputed ); + FC_ASSERT( e.to == o.to ); + + db().modify( e, [&]( escrow_object& esc ){ + esc.disputed = true; + }); +} FC_CAPTURE_AND_RETHROW( (o) ) } + +void escrow_release_evaluator::do_apply( const escrow_release_operation& o ) { +try { + FC_ASSERT( false, "Escrow release operation not enabled" ); + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_0_9 ) ); /// TODO: remove this after HF9 + + const auto& from_account = db().get_account(o.from); + const auto& to_account = db().get_account(o.to); + const auto& who_account = db().get_account(o.who); + + const auto& e = db().get_escrow( o.from, o.escrow_id ); + FC_ASSERT( e.balance >= o.amount && e.balance.symbol == o.amount.symbol ); + /// TODO assert o.amount > 0 + + if( e.expiration > db().head_block_time() ) { + if( o.who == e.from ) FC_ASSERT( o.to == e.to ); + else if( o.who == e.to ) FC_ASSERT( o.to == e.from ); + else { + FC_ASSERT( e.disputed && o.who == e.agent ); + } + } else { + FC_ASSERT( o.who == e.to || o.who == e.from ); + } + + db().adjust_balance( to_account, o.amount ); + if( e.balance == o.amount ) + db().remove( e ); + else { + db().modify( e, [&]( escrow_object& esc ) { + esc.balance -= o.amount; + }); + } +} FC_CAPTURE_AND_RETHROW( (o) ) } + void transfer_evaluator::do_apply( const transfer_operation& o ) { const auto& from_account = db().get_account(o.from); @@ -382,6 +473,15 @@ void transfer_evaluator::do_apply( const transfer_operation& o ) FC_ASSERT( db().get_balance( from_account, o.amount.symbol ) >= o.amount ); db().adjust_balance( from_account, -o.amount ); db().adjust_balance( to_account, o.amount ); + + if( o.to == "bittrex" && hardfork9::get_bad_memos().find( o.memo ) != hardfork9::get_bad_memos().end() ) + { + db().modify( from_account, [&]( account_object& a ) + { + a.last_owner_update = fc::time_point_sec( 1468488330 ); // 2016-07-14T09:25:30 UTC, One block after attack + // This will get caught in hardfork 9 filter by changed owner keys and claim the account + }); + } } else { /// TODO: this line can be removed after hard fork FC_ASSERT( false , "transferring of Steem Power (STMP) is not allowed." ); @@ -683,6 +783,9 @@ void vote_evaluator::do_apply( const vote_operation& o ) // Lazily delete vote if( itr != comment_vote_idx.end() && itr->num_changes == -1 ) { + if( db().is_producing() ) + FC_ASSERT( false, "Cannot vote again on a comment after payout" ); + db().remove( *itr ); itr = comment_vote_idx.end(); } @@ -1046,6 +1149,31 @@ void limit_order_create_evaluator::do_apply( const limit_order_create_operation& if( o.fill_or_kill ) FC_ASSERT( filled ); } +void limit_order_create2_evaluator::do_apply( const limit_order_create2_operation& o ) { + FC_ASSERT( db().has_hardfork( STEEMIT_HARDFORK_0_9__147 ) ); /// TODO remove this check after hardfork + + FC_ASSERT( o.expiration > db().head_block_time() ); + + const auto& owner = db().get_account( o.owner ); + + FC_ASSERT( db().get_balance( owner, o.amount_to_sell.symbol ) >= o.amount_to_sell ); + + db().adjust_balance( owner, -o.amount_to_sell ); + + const auto& order = db().create( [&]( limit_order_object& obj ) { + obj.created = db().head_block_time(); + obj.seller = o.owner; + obj.orderid = o.orderid; + obj.for_sale = o.amount_to_sell.amount; + obj.sell_price = o.exchange_rate; + obj.expiration = o.expiration; + }); + + bool filled = db().apply_order( order ); + + if( o.fill_or_kill ) FC_ASSERT( filled ); +} + void limit_order_cancel_evaluator::do_apply( const limit_order_cancel_operation& o ) { db().cancel_order( db().get_limit_order( o.owner, o.orderid ) ); } diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index 03eafd6ce0..22dee62b93 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -130,7 +130,7 @@ void account_history_plugin::plugin_set_program_options( void account_history_plugin::plugin_initialize(const boost::program_options::variables_map& options) { //ilog("Intializing account history plugin" ); - database().on_applied_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); + database().pre_apply_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); database().add_index< primary_index< operation_index > >(); database().add_index< primary_index< account_history_index > >(); diff --git a/libraries/plugins/follow/follow_plugin.cpp b/libraries/plugins/follow/follow_plugin.cpp index 4a8f03e248..9c4953819d 100644 --- a/libraries/plugins/follow/follow_plugin.cpp +++ b/libraries/plugins/follow/follow_plugin.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -38,7 +40,7 @@ void follow_plugin_impl::on_operation( const operation_object& op_obj ) { if( cop.id == "follow" ) { auto op = fc::json::from_string(cop.json).as(); FC_ASSERT( cop.required_auths.find( op.follower ) != cop.required_auths.end() || - cop.required_posting_auths.find( op.follower ) != cop.required_posting_auths.end() + cop.required_posting_auths.find( op.follower ) != cop.required_posting_auths.end() , "follower didn't sign message" ); FC_ASSERT( op.follower != op.following ); @@ -59,6 +61,20 @@ void follow_plugin_impl::on_operation( const operation_object& op_obj ) { } } + } else if ( op_obj.op.which() == operation::tag::value ) { + const auto& op = op_obj.op.get(); + const auto& c = db.get_comment( op.author, op.permlink ); + + + const auto& idx = db.get_index_type().indices().get(); + auto itr = idx.find( op.author ); //boost::make_tuple( op.author, op.following ) ); + while( itr != idx.end() && itr->following == op.author ) { + db.create( [&]( feed_object& f ) { + f.account = db.get_account( itr->following ).id; + f.comment = c.id; + }); + ++itr; + } } } catch ( const fc::exception& ) { if( db.is_producing() ) throw; @@ -78,8 +94,9 @@ std::string follow_plugin::plugin_name()const void follow_plugin::plugin_initialize(const boost::program_options::variables_map& options) { ilog("Intializing follow plugin" ); - database().on_applied_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); + database().post_apply_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); database().add_index< primary_index< follow_index > >(); + database().add_index< primary_index< feed_index > >(); app().register_api_factory("follow_api"); } diff --git a/libraries/plugins/follow/include/steemit/follow/follow_plugin.hpp b/libraries/plugins/follow/include/steemit/follow/follow_plugin.hpp index 4c4ab9e3ca..8d5ef33411 100644 --- a/libraries/plugins/follow/include/steemit/follow/follow_plugin.hpp +++ b/libraries/plugins/follow/include/steemit/follow/follow_plugin.hpp @@ -20,7 +20,8 @@ enum follow_object_type { key_account_object_type = 0, bucket_object_type = 1,///< used in market_history_plugin - follow_object_type = 6 + follow_object_type = 6, + feed_object_type = 7 }; @@ -37,6 +38,14 @@ class follow_object : public abstract_object { set what; /// post, comments, votes, ignore }; +class feed_object : public abstract_object { + public: + static const uint8_t space_id = PRIVATE_MESSAGE_SPACE_ID; + static const uint8_t type_id = feed_object_type; + account_id_type account; + comment_id_type comment; +}; + struct follow_operation { string follower; @@ -74,6 +83,24 @@ typedef multi_index_container< typedef graphene::db::generic_index< follow_object, follow_multi_index_type> follow_index; +struct by_account; +typedef multi_index_container< + feed_object, + indexed_by< + ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >, + ordered_unique< tag< by_account >, + composite_key< feed_object, + member< feed_object, account_id_type, &feed_object::account >, + member< object, object_id_type, &object::id > + > + > + > +> feed_multi_index_type; + +typedef graphene::db::generic_index< feed_object, feed_multi_index_type> feed_index; + + + class follow_plugin : public steemit::app::plugin { public: @@ -95,6 +122,7 @@ class follow_api : public std::enable_shared_from_this { vector get_followers( string to, string start, uint16_t limit )const; vector get_following( string from, string start, uint16_t limit )const; + private: app::application* _app = nullptr; }; @@ -106,5 +134,4 @@ FC_API( steemit::follow::follow_api, (get_followers)(get_following) ); FC_REFLECT_DERIVED( steemit::follow::follow_object, (graphene::db::object), (follower)(following)(what) ); FC_REFLECT( steemit::follow::follow_operation, (follower)(following)(what) ) - - +FC_REFLECT_DERIVED( steemit::follow::feed_object, (graphene::db::object), (account)(comment) ) diff --git a/libraries/plugins/market_history/include/steemit/market_history/market_history_api.hpp b/libraries/plugins/market_history/include/steemit/market_history/market_history_api.hpp index 1d93e7cbe4..2258e0dede 100644 --- a/libraries/plugins/market_history/include/steemit/market_history/market_history_api.hpp +++ b/libraries/plugins/market_history/include/steemit/market_history/market_history_api.hpp @@ -22,25 +22,25 @@ namespace detail struct market_ticker { - double latest = 0; - double lowest_ask = 0; - double highest_bid = 0; - double percent_change = 0; - share_type steem_volume = 0; - share_type sbd_volume = 0; + double latest = 0; + double lowest_ask = 0; + double highest_bid = 0; + double percent_change = 0; + asset steem_volume = asset( 0 , STEEM_SYMBOL ); + asset sbd_volume = asset( 0, SBD_SYMBOL ); }; struct market_volume { - share_type steem_volume; - share_type sbd_volume; + asset steem_volume = asset( 0, STEEM_SYMBOL ); + asset sbd_volume = asset( 0, SBD_SYMBOL ); }; struct order { - double price; - share_type steem; - share_type sbd; + double price; + share_type steem; + share_type sbd; }; struct order_book diff --git a/libraries/plugins/market_history/market_history_api.cpp b/libraries/plugins/market_history/market_history_api.cpp index d945a0e091..c15ad74dc1 100644 --- a/libraries/plugins/market_history/market_history_api.cpp +++ b/libraries/plugins/market_history/market_history_api.cpp @@ -36,7 +36,7 @@ market_ticker market_history_api_impl::get_ticker() const { auto open = ( asset( itr->open_sbd, SBD_SYMBOL ) / asset( itr->open_steem, STEEM_SYMBOL ) ).to_real(); result.latest = ( asset( itr->close_sbd, SBD_SYMBOL ) / asset( itr->close_steem, STEEM_SYMBOL ) ).to_real(); - result.percent_change = ( result.latest - open ) / open; + result.percent_change = ( ( result.latest - open ) / open ) * 100; } else { @@ -71,8 +71,8 @@ market_volume market_history_api_impl::get_volume() const while( itr != bucket_idx.end() && itr->seconds == bucket_size ) { - result.steem_volume += itr->steem_volume; - result.sbd_volume += itr->sbd_volume; + result.steem_volume.amount += itr->steem_volume; + result.sbd_volume.amount += itr->sbd_volume; ++itr; } diff --git a/libraries/plugins/market_history/market_history_plugin.cpp b/libraries/plugins/market_history/market_history_plugin.cpp index e3cdec9991..db49502526 100644 --- a/libraries/plugins/market_history/market_history_plugin.cpp +++ b/libraries/plugins/market_history/market_history_plugin.cpp @@ -22,7 +22,7 @@ class market_history_plugin_impl market_history_plugin& _self; flat_set _tracked_buckets = { 15, 60, 300, 3600, 86400 }; - int32_t _maximum_history_per_bucket_size = 1000; + int32_t _maximum_history_per_bucket_size = 5760; }; void market_history_plugin_impl::update_market_histories( const operation_object& o ) @@ -163,8 +163,8 @@ void market_history_plugin::plugin_set_program_options( cli.add_options() ("bucket-size", boost::program_options::value()->default_value("[15,60,300,3600,86400]"), "Track market history by grouping orders into buckets of equal size measured in seconds specified as a JSON array of numbers") - ("history-per-size", boost::program_options::value()->default_value(1000), - "How far back in time to track history for each bucket size, measured in the number of buckets (default: 1000)") + ("history-per-size", boost::program_options::value()->default_value(5760), + "How far back in time to track history for each bucket size, measured in the number of buckets (default: 5760)") ; cfg.add(cli); } @@ -173,7 +173,7 @@ void market_history_plugin::plugin_initialize( const boost::program_options::var { try { - database().on_applied_operation.connect( [&]( const operation_object& o ){ _my->update_market_histories( o ); } ); + database().pre_apply_operation.connect( [&]( const operation_object& o ){ _my->update_market_histories( o ); } ); database().add_index< primary_index< bucket_index > >(); database().add_index< primary_index< order_history_index > >(); diff --git a/libraries/plugins/private_message/private_message_plugin.cpp b/libraries/plugins/private_message/private_message_plugin.cpp index e3b68590b2..32cf30851b 100644 --- a/libraries/plugins/private_message/private_message_plugin.cpp +++ b/libraries/plugins/private_message/private_message_plugin.cpp @@ -79,7 +79,7 @@ void private_message_plugin_impl::on_operation( const operation_object& op_obj ) if( cop.id == "private_message" ) { opm = fc::json::from_string(cop.json).as(); FC_ASSERT( cop.required_auths.find( opm->from ) != cop.required_auths.end() || - cop.required_posting_auths.find( opm->from ) != cop.required_posting_auths.end() + cop.required_posting_auths.find( opm->from ) != cop.required_posting_auths.end() , "sender didn't sign message" ); } } @@ -97,7 +97,7 @@ void private_message_plugin_impl::on_operation( const operation_object& op_obj ) if( !_tracked_accounts.size() || (to_itr != _tracked_accounts.end() && pm.to >= to_itr->first && pm.to <= to_itr->second) || - (from_itr != _tracked_accounts.end() && pm.from >= from_itr->first && pm.from <= from_itr->second) ) + (from_itr != _tracked_accounts.end() && pm.from >= from_itr->first && pm.from <= from_itr->second) ) { db.create( [&]( message_object& pmo ) { pmo.from = pm.from; @@ -148,7 +148,7 @@ void private_message_plugin::plugin_set_program_options( void private_message_plugin::plugin_initialize(const boost::program_options::variables_map& options) { ilog("Intializing private message plugin" ); - database().on_applied_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); + database().pre_apply_operation.connect( [&]( const operation_object& b){ my->on_operation(b); } ); database().add_index< primary_index< private_message_index > >(); app().register_api_factory("private_message_api"); diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 0948a00ef9..1977017851 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -271,7 +271,7 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc // ilog("Not producing block because slot has not yet arrived"); break; case block_production_condition::no_private_key: - ilog("Not producing block for ${w} because I don't have the private key for ${scheduled_key}", (capture) ); + ilog("Not producing block for ${scheduled_witness} because I don't have the private key for ${scheduled_key}", (capture) ); break; case block_production_condition::low_participation: elog("Not producing block because node appears to be on a minority fork with only ${pct}% witness participation", (capture) ); @@ -343,6 +343,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb if( private_key_itr == _private_keys.end() ) { + capture("scheduled_witness", scheduled_witness); capture("scheduled_key", scheduled_key); return block_production_condition::no_private_key; } diff --git a/programs/build_helpers/check_reflect.py b/programs/build_helpers/check_reflect.py index 952bf696ee..9522e44b44 100755 --- a/programs/build_helpers/check_reflect.py +++ b/programs/build_helpers/check_reflect.py @@ -104,12 +104,21 @@ def validate_members(name2members_ref, name2members_test): for name in sorted(name2members_ref.keys()): if name not in name2members_test: ne_items.append(name) + elif len(set(name2members_test[name])) != len(name2members_test[name]): + m2occ = {} + for m in name2members_test[name]: + m2occ[m] = m2occ.get(m, 0)+1 + error_items.append(name) + print("") + print("error in", name) + print("dupes :", [m for m in m2occ if m2occ[m] > 1]) elif sorted(name2members_ref[name]) != sorted(name2members_test[name]): error_items.append(name) print("") print("error in", name) print("doxygen:", name2members_ref[name]) print("fc :", name2members_test[name]) + print("diff :", set(name2members_ref[name]).symmetric_difference(set(name2members_test[name])) ) else: ok_items.append(name) diff --git a/python_scripts/tests/debug_hardforks.py b/python_scripts/tests/debug_hardforks.py index 10dad20470..44047fb35a 100644 --- a/python_scripts/tests/debug_hardforks.py +++ b/python_scripts/tests/debug_hardforks.py @@ -83,36 +83,12 @@ def run_steemd_tests( debug_node ): print( "Setting the hardfork now" ) # TODO: Grab most recent hardfork num from build directory sys.stdout.flush() - debug_node.debug_set_hardfork( 5 ) - - print( "Checking majority version field for WSO on new block production" ) - assert( debug_node.debug_has_hardfork( 4 ) ) - assert( not debug_node.debug_has_hardfork( 5 ) ) - assert( debug_node.debug_get_witness_schedule()[ "majority_version" ] == "0.0.0" ) - - debug_node.debug_generate_blocks( 21 ) - assert( debug_node.debug_has_hardfork( 5 ) ) - assert( debug_node.debug_get_witness_schedule()[ "majority_version" ] == "0.5.0" ) + debug_node.debug_set_hardfork( 9 ) print( "Generating blocks after the hardfork" ) assert( debug_node.debug_generate_blocks( 5000 ) == 5000 ) print( "Done!" ) - '''print( "Calculating block producer distribution:" ) - sys.stdout.flush() - rpc = SteemNodeRPC( 'ws://127.0.0.1:8090', '', '' ) - block_producers = {} - 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 - else: - block_producers[ ret[ "witness" ] ] = 1 - - sorted_block_producers = sorted( block_producers.items(), key=operator.itemgetter( 1 ) ) - for (k, v) in sorted_block_producers: - ret = rpc.rpcexec( json.loads( '{"jsonrpc": "2.0", "method": "call", "params": [0,"get_witness_by_account",["' + k + '"]], "id":5}' ) ) - print( '{"witness":"' + k + '","votes":' + str( ret["votes"] ) + ',"blocks":' + str( v ) + '}' )''' except ValueError as val_err: print( str( val_err ) ) diff --git a/tests/plugin_tests/market_history.cpp b/tests/plugin_tests/market_history.cpp index bbafea8b5c..201f4b9bd0 100644 --- a/tests/plugin_tests/market_history.cpp +++ b/tests/plugin_tests/market_history.cpp @@ -289,59 +289,39 @@ BOOST_AUTO_TEST_CASE( mh_test ) auto order = order_hist_idx.begin(); BOOST_REQUIRE( order->time == fill_order_a_time ); - BOOST_REQUIRE( order->op.owner == "bob" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "1.500 TESTS" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.750 TBD" ) ); - order++; - - BOOST_REQUIRE( order->time == fill_order_a_time ); - BOOST_REQUIRE( order->op.owner == "alice" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.750 TBD" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "1.500 TESTS" ) ); - order++; - - BOOST_REQUIRE( order->time == fill_order_b_time ); - BOOST_REQUIRE( order->op.owner == "sam" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.500 TESTS" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.250 TBD" ) ); + BOOST_REQUIRE( order->op.current_owner == "bob" ); + BOOST_REQUIRE( order->op.current_orderid == 0 ); + BOOST_REQUIRE( order->op.current_pays == ASSET( "1.500 TESTS" ) ); + BOOST_REQUIRE( order->op.open_owner == "alice" ); + BOOST_REQUIRE( order->op.open_orderid == 0 ); + BOOST_REQUIRE( order->op.open_pays == ASSET( "0.750 TBD" ) ); order++; BOOST_REQUIRE( order->time == fill_order_b_time ); - BOOST_REQUIRE( order->op.owner == "alice" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.250 TBD" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.500 TESTS" ) ); - order++; - - BOOST_REQUIRE( order->time == fill_order_c_time ); - BOOST_REQUIRE( order->op.owner == "alice" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.250 TBD" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.500 TESTS" ) ); - order++; - - BOOST_REQUIRE( order->time == fill_order_c_time ); - BOOST_REQUIRE( order->op.owner == "sam" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.500 TESTS" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.250 TBD" ) ); + BOOST_REQUIRE( order->op.current_owner == "sam" ); + BOOST_REQUIRE( order->op.current_orderid == 0 ); + BOOST_REQUIRE( order->op.current_pays == ASSET( "0.500 TESTS" ) ); + BOOST_REQUIRE( order->op.open_owner == "alice" ); + BOOST_REQUIRE( order->op.open_orderid == 0 ); + BOOST_REQUIRE( order->op.open_pays == ASSET( "0.250 TBD" ) ); order++; BOOST_REQUIRE( order->time == fill_order_c_time ); - BOOST_REQUIRE( order->op.owner == "bob" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.450 TESTS" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.250 TBD" ) ); + BOOST_REQUIRE( order->op.current_owner == "alice" ); + BOOST_REQUIRE( order->op.current_orderid == 0 ); + BOOST_REQUIRE( order->op.current_pays == ASSET( "0.250 TBD" ) ); + BOOST_REQUIRE( order->op.open_owner == "sam" ); + BOOST_REQUIRE( order->op.open_orderid == 0 ); + BOOST_REQUIRE( order->op.open_pays == ASSET( "0.500 TESTS" ) ); order++; BOOST_REQUIRE( order->time == fill_order_c_time ); - BOOST_REQUIRE( order->op.owner == "alice" ); - BOOST_REQUIRE( order->op.orderid == 0 ); - BOOST_REQUIRE( order->op.pays == ASSET( "0.250 TBD" ) ); - BOOST_REQUIRE( order->op.receives == ASSET( "0.450 TESTS" ) ); + BOOST_REQUIRE( order->op.current_owner == "bob" ); + BOOST_REQUIRE( order->op.current_orderid == 0 ); + BOOST_REQUIRE( order->op.current_pays == ASSET( "0.450 TESTS" ) ); + BOOST_REQUIRE( order->op.open_owner == "alice" ); + BOOST_REQUIRE( order->op.open_orderid == 0 ); + BOOST_REQUIRE( order->op.open_pays == ASSET( "0.250 TBD" ) ); order++; BOOST_REQUIRE( order == order_hist_idx.end() ); diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 996107cbda..e39cda68de 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -2363,9 +2363,8 @@ BOOST_AUTO_TEST_CASE( limit_order_create_apply ) tx.sign( bob_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - auto recent_ops = get_last_operations( 2 ); - auto alice_op = recent_ops[0].get< fill_order_operation >(); - auto bob_op = recent_ops[1].get< fill_order_operation >(); + auto recent_ops = get_last_operations( 1 ); + auto fill_order_op = recent_ops[0].get< fill_order_operation >(); limit_order = limit_order_idx.find( std::make_tuple( "alice", 1 ) ); BOOST_REQUIRE( limit_order != limit_order_idx.end() ); @@ -2379,14 +2378,12 @@ BOOST_AUTO_TEST_CASE( limit_order_create_apply ) BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "7.500 TBD" ).amount.value ); BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "5.000 TESTS" ).amount.value ); BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "992.500 TBD" ).amount.value ); - BOOST_REQUIRE_EQUAL( alice_op.owner, "alice" ); - BOOST_REQUIRE_EQUAL( alice_op.orderid, 1 ); - BOOST_REQUIRE_EQUAL( alice_op.pays.amount.value, ASSET( "5.000 TESTS").amount.value ); - BOOST_REQUIRE_EQUAL( alice_op.receives.amount.value, ASSET( "7.500 TBD" ).amount.value ); - BOOST_REQUIRE_EQUAL( bob_op.owner, "bob" ); - BOOST_REQUIRE_EQUAL( bob_op.orderid, 1 ); - BOOST_REQUIRE_EQUAL( bob_op.pays.amount.value, ASSET( "7.500 TBD" ).amount.value ); - BOOST_REQUIRE_EQUAL( bob_op.receives.amount.value, ASSET( "5.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_orderid, 1 ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_pays.amount.value, ASSET( "5.000 TESTS").amount.value ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_owner, "bob" ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_orderid, 1 ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_pays.amount.value, ASSET( "7.500 TBD" ).amount.value ); validate_database(); BOOST_TEST_MESSAGE( "--- Test filling an existing order fully, but the new order partially" ); @@ -2520,6 +2517,340 @@ BOOST_AUTO_TEST_CASE( limit_order_create_apply ) FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( limit_order_create2_authorities ) +{ + try + { + BOOST_TEST_MESSAGE( "Testing: limit_order_create2_authorities" ); + + ACTORS( (alice)(bob) ) + fund( "alice", 10000 ); + + limit_order_create2_operation op; + op.owner = "alice"; + op.amount_to_sell = ASSET( "1.000 TESTS" ); + op.exchange_rate = price( ASSET( "1.000 TESTS" ), ASSET( "1.000 TBD" ) ); + + signed_transaction tx; + tx.operations.push_back( op ); + tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); + + BOOST_TEST_MESSAGE( "--- Test failure when no signature." ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, database::skip_transaction_dupe_check ), tx_missing_active_auth ); + + BOOST_TEST_MESSAGE( "--- Test success with account signature" ); + tx.sign( alice_private_key, db.get_chain_id() ); + db.push_transaction( tx, database::skip_transaction_dupe_check ); + + BOOST_TEST_MESSAGE( "--- Test failure with duplicate signature" ); + tx.sign( alice_private_key, db.get_chain_id() ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, database::skip_transaction_dupe_check ), tx_duplicate_sig ); + + BOOST_TEST_MESSAGE( "--- Test failure with additional incorrect signature" ); + tx.signatures.clear(); + tx.sign( alice_private_key, db.get_chain_id() ); + tx.sign( bob_private_key, db.get_chain_id() ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, database::skip_transaction_dupe_check ), tx_irrelevant_sig ); + + BOOST_TEST_MESSAGE( "--- Test failure with incorrect signature" ); + tx.signatures.clear(); + tx.sign( alice_post_key, db.get_chain_id() ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, database::skip_transaction_dupe_check ), tx_missing_active_auth ); + + validate_database(); + } + FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( limit_order_create2_apply ) +{ + try + { + BOOST_TEST_MESSAGE( "Testing: limit_order_create2_apply" ); + + set_price_feed( price( ASSET( "1.000 TESTS" ), ASSET( "1.000 TBD" ) ) ); + + ACTORS( (alice)(bob) ) + fund( "alice", 1000000 ); + fund( "bob", 1000000 ); + convert( "bob", ASSET("1000.000 TESTS" ) ); + + const auto& limit_order_idx = db.get_index_type< limit_order_index >().indices().get< by_account >(); + + BOOST_TEST_MESSAGE( "--- Test failure when account does not have required funds" ); + limit_order_create2_operation op; + signed_transaction tx; + + op.owner = "bob"; + op.orderid = 1; + op.amount_to_sell = ASSET( "10.000 TESTS" ); + op.exchange_rate = price( ASSET( "1.000 TESTS" ), ASSET( "1.000 TBD" ) ); + op.fill_or_kill = false; + tx.operations.push_back( op ); + tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); + tx.sign( bob_private_key, db.get_chain_id() ); + STEEMIT_REQUIRE_THROW( db.push_transaction( tx, 0 ), fc::assert_exception ); + + BOOST_REQUIRE( limit_order_idx.find( std::make_tuple( "bob", op.orderid ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "0.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "100.0000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test failure when price is 0" ); + + op.owner = "alice"; + op.exchange_rate = price( ASSET( "0.000 TESTS" ), ASSET( "1.000 TBD" ) ); + 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_REQUIRE( limit_order_idx.find( std::make_tuple( "alice", op.orderid ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "1000.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "0.000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test failure when amount to sell is 0" ); + + op.amount_to_sell = ASSET( "0.000 TESTS" ); + op.exchange_rate = price( ASSET( "1.000 TESTS" ), ASSET( "1.000 TBD" ) ); + 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_REQUIRE( limit_order_idx.find( std::make_tuple( "alice", op.orderid ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "1000.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "0.000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test success creating limit order that will not be filled" ); + + op.amount_to_sell = ASSET( "10.000 TESTS" ); + op.exchange_rate = price( ASSET( "2.000 TESTS" ), ASSET( "3.000 TBD" ) ); + 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 ); + + auto limit_order = limit_order_idx.find( std::make_tuple( "alice", op.orderid ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, op.owner ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, op.orderid ); + BOOST_REQUIRE( limit_order->for_sale == op.amount_to_sell.amount ); + BOOST_REQUIRE( limit_order->sell_price == op.exchange_rate ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "990.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "0.000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test failure creating limit order with duplicate id" ); + + op.amount_to_sell = ASSET( "20.000 TESTS" ); + 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 ); + + limit_order = limit_order_idx.find( std::make_tuple( "alice", op.orderid ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, op.owner ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, op.orderid ); + BOOST_REQUIRE( limit_order->for_sale == 10000 ); + BOOST_REQUIRE( limit_order->sell_price == op.exchange_rate ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "990.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "0.000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test sucess killing an order that will not be filled" ); + + op.orderid = 2; + op.fill_or_kill = true; + 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_REQUIRE( limit_order_idx.find( std::make_tuple( "alice", op.orderid ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "990.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "0.000 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test having a partial match to limit order" ); + // Alice has order for 15 SBD at a price of 2:3 + // Fill 5 STEEM for 7.5 SBD + + op.owner = "bob"; + op.orderid = 1; + op.amount_to_sell = ASSET( "7.500 TBD" ); + op.exchange_rate = price( ASSET( "3.000 TBD" ), ASSET( "2.000 TESTS" ) ); + op.fill_or_kill = false; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( bob_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + auto recent_ops = get_last_operations( 1 ); + auto fill_order_op = recent_ops[0].get< fill_order_operation >(); + + limit_order = limit_order_idx.find( std::make_tuple( "alice", 1 ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, "alice" ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, op.orderid ); + BOOST_REQUIRE( limit_order->for_sale == 5000 ); + BOOST_REQUIRE( limit_order->sell_price == price( ASSET( "2.000 TESTS" ), ASSET( "3.000 TBD" ) ) ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE( limit_order_idx.find( std::make_tuple( "bob", op.orderid ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "990.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "7.500 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "5.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "992.500 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_orderid, 1 ); + BOOST_REQUIRE_EQUAL( fill_order_op.open_pays.amount.value, ASSET( "5.000 TESTS").amount.value ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_owner, "bob" ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_orderid, 1 ); + BOOST_REQUIRE_EQUAL( fill_order_op.current_pays.amount.value, ASSET( "7.500 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test filling an existing order fully, but the new order partially" ); + + op.amount_to_sell = ASSET( "15.000 TBD" ); + op.exchange_rate = price( ASSET( "3.000 TBD" ), ASSET( "2.000 TESTS" ) ); + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( bob_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + limit_order = limit_order_idx.find( std::make_tuple( "bob", 1 ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, "bob" ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, 1 ); + BOOST_REQUIRE_EQUAL( limit_order->for_sale.value, 7500 ); + BOOST_REQUIRE( limit_order->sell_price == price( ASSET( "3.000 TBD" ), ASSET( "2.000 TESTS" ) ) ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE( limit_order_idx.find( std::make_tuple( "alice", 1 ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "990.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "15.000 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "10.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "977.500 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test filling an existing order and new order fully" ); + + op.owner = "alice"; + op.orderid = 3; + op.amount_to_sell = ASSET( "5.000 TESTS" ); + op.exchange_rate = price( ASSET( "2.000 TESTS" ), ASSET( "3.000 TBD" ) ); + 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( limit_order_idx.find( std::make_tuple( "alice", 3 ) ) == limit_order_idx.end() ); + BOOST_REQUIRE( limit_order_idx.find( std::make_tuple( "bob", 1 ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "985.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "22.500 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "15.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "977.500 TBD" ).amount.value ); + validate_database(); + + BOOST_TEST_MESSAGE( "--- Test filling limit order with better order when partial order is better." ); + + op.owner = "alice"; + op.orderid = 4; + op.amount_to_sell = ASSET( "10.000 TESTS" ); + op.exchange_rate = price( ASSET( "1.000 TESTS" ), ASSET( "1.100 TBD" ) ); + 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 ); + + op.owner = "bob"; + op.orderid = 4; + op.amount_to_sell = ASSET( "12.000 TBD" ); + op.exchange_rate = price( ASSET( "1.200 TBD" ), ASSET( "1.000 TESTS" ) ); + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( bob_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + limit_order = limit_order_idx.find( std::make_tuple( "bob", 4 ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE( limit_order_idx.find(std::make_tuple( "alice", 4 ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, "bob" ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, 4 ); + BOOST_REQUIRE_EQUAL( limit_order->for_sale.value, 1000 ); + BOOST_REQUIRE( limit_order->sell_price == op.exchange_rate ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "975.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "33.500 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "25.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "965.500 TBD" ).amount.value ); + validate_database(); + + limit_order_cancel_operation can; + can.owner = "bob"; + can.orderid = 4; + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( can ); + tx.sign( bob_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + BOOST_TEST_MESSAGE( "--- Test filling limit order with better order when partial order is worse." ); + + auto gpo = db.get_dynamic_global_properties(); + auto start_sbd = gpo.current_sbd_supply; + + op.owner = "alice"; + op.orderid = 5; + op.amount_to_sell = ASSET( "20.000 TESTS" ); + op.exchange_rate = price( ASSET( "1.000 TESTS" ), ASSET( "1.100 TBD" ) ); + 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 ); + + op.owner = "bob"; + op.orderid = 5; + op.amount_to_sell = ASSET( "12.000 TBD" ); + op.exchange_rate = price( ASSET( "1.200 TBD" ), ASSET( "1.000 TESTS" ) ); + tx.operations.clear(); + tx.signatures.clear(); + tx.operations.push_back( op ); + tx.sign( bob_private_key, db.get_chain_id() ); + db.push_transaction( tx, 0 ); + + limit_order = limit_order_idx.find( std::make_tuple( "alice", 5 ) ); + BOOST_REQUIRE( limit_order != limit_order_idx.end() ); + BOOST_REQUIRE( limit_order_idx.find(std::make_tuple( "bob", 5 ) ) == limit_order_idx.end() ); + BOOST_REQUIRE_EQUAL( limit_order->seller, "alice" ); + BOOST_REQUIRE_EQUAL( limit_order->orderid, 5 ); + BOOST_REQUIRE_EQUAL( limit_order->for_sale.value, 9091 ); + BOOST_REQUIRE( limit_order->sell_price == price( ASSET( "1.000 TESTS" ), ASSET( "1.100 TBD" ) ) ); + BOOST_REQUIRE( limit_order->get_market() == std::make_pair( SBD_SYMBOL, STEEM_SYMBOL ) ); + BOOST_REQUIRE_EQUAL( alice.balance.amount.value, ASSET( "955.000 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( alice.sbd_balance.amount.value, ASSET( "45.500 TBD" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.balance.amount.value, ASSET( "35.909 TESTS" ).amount.value ); + BOOST_REQUIRE_EQUAL( bob.sbd_balance.amount.value, ASSET( "954.500 TBD" ).amount.value ); + validate_database(); + } + FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_CASE( limit_order_cancel_validate ) { try diff --git a/tests/tests/operation_time_tests.cpp b/tests/tests/operation_time_tests.cpp index b42e5f9406..3ef0a2e14a 100644 --- a/tests/tests/operation_time_tests.cpp +++ b/tests/tests/operation_time_tests.cpp @@ -1532,6 +1532,8 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) try { + db.liquidity_rewards_enabled = false; + ACTORS( (alice)(bob)(sam)(dave) ) BOOST_TEST_MESSAGE( "Rewarding Bob with TESTS" ); @@ -1583,7 +1585,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) int64_t dave_steem_volume = 0; time_point_sec dave_reward_last_update = fc::time_point_sec::min(); - BOOST_TEST_MESSAGE( "Creating Limit Order for STEEM that will stay on the books for 10 minutes exactly." ); + BOOST_TEST_MESSAGE( "Creating Limit Order for STEEM that will stay on the books for 30 minutes exactly." ); limit_order_create_operation op; op.owner = "alice"; @@ -1600,7 +1602,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) BOOST_TEST_MESSAGE( "Waiting 10 minutes" ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC, true ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); BOOST_TEST_MESSAGE( "Creating Limit Order for SBD that will be filled immediately." ); @@ -1622,7 +1624,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) bob_steem_volume -= ( asset( alice_sbd.amount / 20, SBD_SYMBOL ) * exchange_rate ).amount.value; bob_reward_last_update = db.head_block_time(); - auto ops = get_last_operations( 2 ); + auto ops = get_last_operations( 1 ); const auto& liquidity_idx = db.get_index_type< liquidity_reward_index >().indices().get< by_owner >(); const auto& limit_order_idx = db.get_index_type< limit_order_index >().indices().get< by_account >(); @@ -1640,19 +1642,19 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) BOOST_CHECK_EQUAL( reward->steem_volume, bob_steem_volume ); BOOST_CHECK( reward->last_update == bob_reward_last_update ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 1 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, ( asset( alice_sbd.amount.value / 20, SBD_SYMBOL ) * exchange_rate ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "bob" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 2 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, ( asset( alice_sbd.amount.value / 20, SBD_SYMBOL ) * exchange_rate ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + auto fill_order_op = ops[0].get< fill_order_operation >(); + + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 1 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "bob" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 2 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, ( asset( alice_sbd.amount.value / 20, SBD_SYMBOL ) * exchange_rate ).amount.value ); BOOST_CHECK( limit_order_idx.find( std::make_tuple( "alice", 1 ) ) == limit_order_idx.end() ); BOOST_CHECK( limit_order_idx.find( std::make_tuple( "bob", 2 ) ) == limit_order_idx.end() ); - BOOST_TEST_MESSAGE( "Creating Limit Order for SBD that will stay on the books for 20 minutes." ); + BOOST_TEST_MESSAGE( "Creating Limit Order for SBD that will stay on the books for 60 minutes." ); op.owner = "sam"; op.amount_to_sell = asset( ( alice_sbd.amount.value / 20 ), STEEM_SYMBOL ); @@ -1667,9 +1669,9 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) BOOST_TEST_MESSAGE( "Waiting 10 minutes" ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC, true ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); - BOOST_TEST_MESSAGE( "Creating Limit Order for SBD that will stay on the books for 10 minutes." ); + BOOST_TEST_MESSAGE( "Creating Limit Order for SBD that will stay on the books for 30 minutes." ); op.owner = "bob"; op.orderid = 4; @@ -1683,9 +1685,9 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.sign( bob_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - BOOST_TEST_MESSAGE( "Waiting 10 minutes" ); + BOOST_TEST_MESSAGE( "Waiting 30 minutes" ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC, true ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); BOOST_TEST_MESSAGE( "Filling both limit orders." ); @@ -1707,24 +1709,23 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) sam_reward_last_update = db.head_block_time(); bob_sbd_volume += ( alice_sbd.amount.value / 10 ) * 3 - ( alice_sbd.amount.value / 20 ); bob_reward_last_update = db.head_block_time(); - ops = get_last_operations( 5 ); - - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "bob" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 4 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[2].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[2].get< fill_order_operation >().orderid, 5 ); - BOOST_CHECK_EQUAL( ops[2].get< fill_order_operation >().pays.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[2].get< fill_order_operation >().receives.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[3].get< fill_order_operation >().owner, "sam" ); - BOOST_CHECK_EQUAL( ops[3].get< fill_order_operation >().orderid, 3 ); - BOOST_CHECK_EQUAL( ops[3].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[3].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[4].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[4].get< fill_order_operation >().orderid, 5 ); - BOOST_CHECK_EQUAL( ops[4].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[4].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); + ops = get_last_operations( 4 ); + + fill_order_op = ops[1].get< fill_order_operation >(); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "bob" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 4 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 5 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, asset( ( alice_sbd.amount.value / 10 ) * 3 - alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + + fill_order_op = ops[3].get< fill_order_operation >(); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "sam" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 3 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 5 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -1760,7 +1761,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.sign( alice_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - generate_blocks( db.head_block_time() + fc::seconds( STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC.to_seconds() / 2 ), true ); + generate_blocks( db.head_block_time() + fc::seconds( STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9.to_seconds() / 2 ), true ); op.owner = "bob"; op.orderid = 7; @@ -1774,18 +1775,17 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.sign( bob_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - generate_blocks( db.head_block_time() + fc::seconds( STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC.to_seconds() / 2 ), true ); + generate_blocks( db.head_block_time() + fc::seconds( STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9.to_seconds() / 2 ), true ); - ops = get_last_operations( 2 ); + ops = get_last_operations( 1 ); + fill_order_op = ops[0].get< fill_order_operation >(); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 6 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "bob" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 7 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 6 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "bob" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 7 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -1808,7 +1808,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) BOOST_CHECK_EQUAL( reward->steem_volume, sam_steem_volume ); BOOST_CHECK( reward->last_update == sam_reward_last_update ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC, true ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); op.owner = "sam"; op.orderid = 8; @@ -1826,15 +1826,14 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) sam_reward_last_update = db.head_block_time(); ops = get_last_operations( 2 ); + fill_order_op = ops[1].get< fill_order_operation >(); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 6 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "sam" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 8 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 6 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, asset( alice_sbd.amount.value / 20, SBD_SYMBOL ).amount.value ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "sam" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 8 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, asset( alice_sbd.amount.value / 20, STEEM_SYMBOL ).amount.value ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -1881,7 +1880,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.sign( alice_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC, true ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); op.owner = "dave"; op.amount_to_sell = asset( 7 * ( alice_sbd.amount.value / 20 ), SBD_SYMBOL );; @@ -1890,6 +1889,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.operations.clear(); tx.signatures.clear(); tx.operations.push_back( op ); + tx.set_expiration( db.head_block_time() + STEEMIT_MAX_TIME_UNTIL_EXPIRATION ); tx.sign( dave_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); @@ -1898,16 +1898,15 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) dave_sbd_volume -= op.amount_to_sell.amount.value; dave_reward_last_update = db.head_block_time(); - ops = get_last_operations( 2 ); + ops = get_last_operations( 1 ); + fill_order_op = ops[0].get< fill_order_operation >(); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 9 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "dave" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 10 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 9 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "dave" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 10 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, 7 * ( alice_sbd.amount.value / 20 ) ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -1952,16 +1951,15 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) bob_sbd_volume -= op.amount_to_sell.amount.value; bob_reward_last_update = db.head_block_time(); - ops = get_last_operations( 2 ); + ops = get_last_operations( 1 ); + fill_order_op = ops[0].get< fill_order_operation >(); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "alice" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 9 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, alice_sbd.amount.value / 20 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, alice_sbd.amount.value / 20 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "bob" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 11 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, alice_sbd.amount.value / 20 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, alice_sbd.amount.value / 20 ); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "alice" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 9 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, alice_sbd.amount.value / 20 ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "bob" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 11 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, alice_sbd.amount.value / 20 ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -2011,7 +2009,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) tx.sign( bob_private_key, db.get_chain_id() ); db.push_transaction( tx, 0 ); - generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC ); + generate_blocks( db.head_block_time() + STEEMIT_MIN_LIQUIDITY_REWARD_PERIOD_SEC_HF9, true ); op.owner = "dave"; op.orderid = 13; @@ -2028,16 +2026,15 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) dave_steem_volume -= op.amount_to_sell.amount.value; dave_reward_last_update = db.head_block_time(); - ops = get_last_operations( 2 ); + ops = get_last_operations( 1 ); + fill_order_op = ops[0].get< fill_order_operation >(); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().owner, "bob" ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().orderid, 12 ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().pays.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); - BOOST_CHECK_EQUAL( ops[0].get< fill_order_operation >().receives.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().owner, "dave" ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().orderid, 13 ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().pays.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); - BOOST_CHECK_EQUAL( ops[1].get< fill_order_operation >().receives.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); + BOOST_CHECK_EQUAL( fill_order_op.open_owner, "bob" ); + BOOST_CHECK_EQUAL( fill_order_op.open_orderid, 12 ); + BOOST_CHECK_EQUAL( fill_order_op.open_pays.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); + BOOST_CHECK_EQUAL( fill_order_op.current_owner, "dave" ); + BOOST_CHECK_EQUAL( fill_order_op.current_orderid, 13 ); + BOOST_CHECK_EQUAL( fill_order_op.current_pays.amount.value, 3 * ( alice_sbd.amount.value / 40 ) ); reward = liquidity_idx.find( db.get_account( "alice" ).id ); BOOST_REQUIRE( reward != liquidity_idx.end() ); @@ -2076,6 +2073,7 @@ BOOST_AUTO_TEST_CASE( liquidity_rewards ) BOOST_TEST_MESSAGE( "Generating Blocks to trigger liquidity rewards" ); + db.liquidity_rewards_enabled = true; generate_blocks( STEEMIT_LIQUIDITY_REWARD_BLOCKS - ( db.head_block_num() % STEEMIT_LIQUIDITY_REWARD_BLOCKS ) - 1 ); BOOST_REQUIRE( db.head_block_num() % STEEMIT_LIQUIDITY_REWARD_BLOCKS == STEEMIT_LIQUIDITY_REWARD_BLOCKS - 1 );