From 6999bb132603200946e2a49b4c3d2998b98cf1d7 Mon Sep 17 00:00:00 2001 From: pbattu123 Date: Tue, 14 Apr 2020 13:44:53 -0300 Subject: [PATCH] sweeps winner_ticket_id changes --- libraries/chain/asset_object.cpp | 43 +++++++++++++ libraries/chain/hardfork.d/5050-1.hf | 4 ++ .../include/graphene/chain/asset_object.hpp | 1 + .../graphene/chain/protocol/lottery_ops.hpp | 8 ++- tests/tests/lottery_tests.cpp | 61 +++++++++++++++++++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/hardfork.d/5050-1.hf diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index 88e5dfca..82951d79 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -23,6 +23,8 @@ */ #include #include +#include +#include #include #include @@ -185,6 +187,41 @@ vector asset_object::get_holders( database& db ) const return holders; } +vector asset_object::get_ticket_ids( database& db ) const +{ + auto& asset_bal_idx = db.get_index_type< account_balance_index >().indices().get< by_asset_balance >(); + vector ids; + const auto range = asset_bal_idx.equal_range( boost::make_tuple( get_id() ) ); + + for( const account_balance_object& bal : boost::make_iterator_range( range.first, range.second ) ) + { + const auto& stats = bal.owner(db).statistics(db); + const account_transaction_history_object* ath = static_cast(&stats.most_recent_op(db)); + for( uint64_t balance = bal.balance.value; balance > 0;) + { + if(ath != nullptr) + { + const operation_history_object& oho = db.get( ath->operation_id ); + if( oho.op.which() == operation::tag::value && get_id() == oho.op.get().lottery) + { + uint64_t tickets_count = oho.op.get().tickets_to_buy; + ids.insert(ids.end(), tickets_count, oho.id.instance()); + balance -= tickets_count; + assert(balance >= 0); + } + + if( ath->next == account_transaction_history_id_type() ) + { + ath = nullptr; + break; + } + else ath = db.find(ath->next); + } + } + } + return ids; +} + void asset_object::distribute_benefactors_part( database& db ) { transaction_evaluation_state eval( &db ); @@ -206,6 +243,7 @@ map< account_id_type, vector< uint16_t > > asset_object::distribute_winners_part transaction_evaluation_state eval( &db ); auto holders = get_holders( db ); + vector ticket_ids = get_ticket_ids(db); FC_ASSERT( dynamic_data( db ).current_supply == holders.size() ); map > structurized_participants; for( account_id_type holder : holders ) @@ -234,6 +272,11 @@ map< account_id_type, vector< uint16_t > > asset_object::distribute_winners_part reward_op.lottery = get_id(); reward_op.is_benefactor_reward = false; reward_op.winner = holders[winner_num]; + if(db.head_block_time() > HARDFORK_5050_1_TIME && ticket_ids.size() >= winner_num) + { + const static_variant tkt_id = ticket_ids[winner_num]; + reward_op.winner_ticket_id = tkt_id; + } reward_op.win_percentage = tickets[c]; reward_op.amount = asset( jackpot * tickets[c] * ( 1. - sweeps_distribution_percentage / (double)GRAPHENE_100_PERCENT ) / GRAPHENE_100_PERCENT , db.get_balance(id).asset_id ); db.apply_operation(eval, reward_op); diff --git a/libraries/chain/hardfork.d/5050-1.hf b/libraries/chain/hardfork.d/5050-1.hf new file mode 100644 index 00000000..51c12732 --- /dev/null +++ b/libraries/chain/hardfork.d/5050-1.hf @@ -0,0 +1,4 @@ +// 5050_1 HARDFORK Thursday, 22 April 2020 20:00:00 GMT +#ifndef HARDFORK_5050_1_TIME +#define HARDFORK_5050_1_TIME (fc::time_point_sec( 1587585600 )) +#endif diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 8978a6d1..d8c65e89 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -134,6 +134,7 @@ namespace graphene { namespace chain { optional lottery_options; time_point_sec get_lottery_expiration() const; vector get_holders( database& db ) const; + vector get_ticket_ids( database& db ) const; void distribute_benefactors_part( database& db ); map< account_id_type, vector< uint16_t > > distribute_winners_part( database& db ); void distribute_sweeps_holders_part( database& db ); diff --git a/libraries/chain/include/graphene/chain/protocol/lottery_ops.hpp b/libraries/chain/include/graphene/chain/protocol/lottery_ops.hpp index 32d70a37..4f512bce 100644 --- a/libraries/chain/include/graphene/chain/protocol/lottery_ops.hpp +++ b/libraries/chain/include/graphene/chain/protocol/lottery_ops.hpp @@ -52,6 +52,8 @@ namespace graphene { namespace chain { share_type calculate_fee( const fee_parameters_type& k )const; }; + typedef static_variant ticket_num; + /** * @ingroup operations */ @@ -73,7 +75,7 @@ namespace graphene { namespace chain { // true if recieved from benefators section of lottery; false otherwise bool is_benefactor_reward; - extensions_type extensions; + ticket_num winner_ticket_id; account_id_type fee_payer()const { return account_id_type(); } void validate()const {}; @@ -114,7 +116,7 @@ FC_REFLECT( graphene::chain::ticket_purchase_operation, ) FC_REFLECT( graphene::chain::ticket_purchase_operation::fee_parameters_type, (fee) ) - +FC_REFLECT_TYPENAME( graphene::chain::ticket_num ) FC_REFLECT( graphene::chain::lottery_reward_operation, (fee) (lottery) @@ -122,7 +124,7 @@ FC_REFLECT( graphene::chain::lottery_reward_operation, (amount) (win_percentage) (is_benefactor_reward) - (extensions) + (winner_ticket_id) ) FC_REFLECT( graphene::chain::lottery_reward_operation::fee_parameters_type, (fee) ) diff --git a/tests/tests/lottery_tests.cpp b/tests/tests/lottery_tests.cpp index b0f234e2..063c15c1 100644 --- a/tests/tests/lottery_tests.cpp +++ b/tests/tests/lottery_tests.cpp @@ -63,6 +63,7 @@ BOOST_AUTO_TEST_CASE( create_lottery_asset_test ) lottery_options.end_date = db.head_block_time() + fc::minutes(5); lottery_options.ticket_price = asset(100); lottery_options.winning_tickets = { 5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 5 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT, 10 * GRAPHENE_1_PERCENT }; + //lottery_options.winning_tickets = { 75 * GRAPHENE_1_PERCENT }; lottery_options.is_active = test_asset_id.instance.value % 2; lottery_options.ending_on_soldout = true; @@ -482,4 +483,64 @@ BOOST_AUTO_TEST_CASE( try_to_end_empty_lottery_test ) } } +BOOST_AUTO_TEST_CASE( lottery_winner_ticket_id_test ) +{ + try { + asset_id_type test_asset_id = db.get_index().get_next_id(); + INVOKE( create_lottery_asset_test ); + auto test_asset = test_asset_id(db); + for( int i = 1; i < 4; ++i ) { + transfer(account_id_type(), account_id_type(i), asset(2000000)); + } + for( int i = 1; i < 4; ++i ) { + if( i == 4 ) continue; + ticket_purchase_operation tpo; + tpo.buyer = account_id_type(i); + tpo.lottery = test_asset.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + graphene::chain::test::set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + + for( int i = 1; i < 4; ++i ) { + if( i == 4 ) continue; + ticket_purchase_operation tpo; + tpo.buyer = account_id_type(i); + tpo.lottery = test_asset.id; + tpo.tickets_to_buy = 1; + tpo.amount = asset(100); + trx.operations.push_back(std::move(tpo)); + graphene::chain::test::set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + test_asset = test_asset_id(db); + uint64_t creator_balance_before_end = db.get_balance( account_id_type(), asset_id_type() ).amount.value; + uint64_t jackpot = db.get_balance( test_asset.get_id() ).amount.value; + uint16_t winners_part = 0; + for( uint8_t win: test_asset.lottery_options->winning_tickets ) + winners_part += win; + + while( db.head_block_time() < ( test_asset.lottery_options->end_date ) ) + generate_block(); + + auto op_history = get_operation_history( account_id_type(1) ); //Can observe operation 79 to verify winner ticket number + for( auto h: op_history ) { + idump((h)); + } + + BOOST_CHECK( db.get_balance( test_asset.get_id() ).amount.value == 0 ); + uint64_t creator_recieved = db.get_balance( account_id_type(), asset_id_type() ).amount.value - creator_balance_before_end; + test_asset = test_asset_id(db); + BOOST_CHECK(jackpot * test_asset.lottery_options->benefactors[0].share / GRAPHENE_100_PERCENT == creator_recieved); + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + BOOST_AUTO_TEST_SUITE_END()