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()