diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 12524329..6c36fda4 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -156,7 +156,8 @@ namespace graphene { namespace chain { impl_budget_record_object_type, impl_special_authority_object_type, impl_buyback_object_type, - impl_fba_accumulator_object_type + impl_fba_accumulator_object_type, + impl_tournament_details_object_type }; //typedef fc::unsigned_int object_id_type; @@ -210,6 +211,7 @@ namespace graphene { namespace chain { class special_authority_object; class buyback_object; class fba_accumulator_object; + class tournament_details_object; typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; @@ -230,6 +232,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_special_authority_object_type, special_authority_object > special_authority_id_type; typedef object_id< implementation_ids, impl_buyback_object_type, buyback_object > buyback_id_type; typedef object_id< implementation_ids, impl_fba_accumulator_object_type, fba_accumulator_object > fba_accumulator_id_type; + typedef object_id< implementation_ids, impl_tournament_details_object_type, tournament_details_object > tournament_details_id_type; typedef fc::array symbol_type; typedef fc::ripemd160 block_id_type; @@ -364,6 +367,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_special_authority_object_type) (impl_buyback_object_type) (impl_fba_accumulator_object_type) + (impl_tournament_details_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) @@ -396,6 +400,7 @@ FC_REFLECT_TYPENAME( graphene::chain::budget_record_id_type ) FC_REFLECT_TYPENAME( graphene::chain::special_authority_id_type ) FC_REFLECT_TYPENAME( graphene::chain::buyback_id_type ) FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/tournament_evaluator.hpp b/libraries/chain/include/graphene/chain/tournament_evaluator.hpp index 85265146..d5b70d04 100644 --- a/libraries/chain/include/graphene/chain/tournament_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/tournament_evaluator.hpp @@ -16,6 +16,11 @@ namespace graphene { namespace chain { class tournament_join_evaluator : public evaluator { + private: + const tournament_object* _tournament_obj = nullptr; + const tournament_details_object* _tournament_details_obj = nullptr; + const account_object* _payer_account = nullptr; + const asset_object* _buy_in_asset_type = nullptr; public: typedef tournament_join_operation operation_type; diff --git a/libraries/chain/include/graphene/chain/tournament_object.hpp b/libraries/chain/include/graphene/chain/tournament_object.hpp index 3ddf9256..e77b99c7 100644 --- a/libraries/chain/include/graphene/chain/tournament_object.hpp +++ b/libraries/chain/include/graphene/chain/tournament_object.hpp @@ -7,6 +7,22 @@ namespace graphene { namespace chain { class database; using namespace graphene::db; + /// The tournament object has a lot of details, most of which are only of interest to anyone + /// involved in the tournament. The main `tournament_object` contains all of the information + /// needed to display an overview of the tournament, this object contains the rest. + class tournament_details_object : public graphene::db::abstract_object + { + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = impl_tournament_details_object_type; + + /// List of players registered for this tournament + flat_set registered_players; + + /// List of payers who have contributed to the prize pool + flat_map payers; + }; + class tournament_object : public graphene::db::abstract_object { public: @@ -24,16 +40,21 @@ namespace graphene { namespace chain { /// If the tournament has ended, the time it ended optional end_time; - /// List of players registered for this tournament - flat_set registered_players; + /// Total prize pool accumulated + /// This is the sum of all payers in the details object, and will be + /// registered_players.size() * buy_in_amount + share_type prize_pool; - /// List of payers who have contributed to the prize pool - flat_map payers; + /// The number of players registered for the tournament + /// (same as the details object's registered_players.size(), here to avoid + /// the GUI having to get the details object) + uint32_t registered_players = 0; - /// Total prize pool accumulated ((sum of buy_ins, usually registered_players.size() * buy_in_amount) - asset prize_pool; + /// Detailed information on this tournament + tournament_details_id_type tournament_details_id; }; + struct by_registration_deadline {}; typedef multi_index_container< tournament_object, indexed_by< @@ -44,8 +65,13 @@ namespace graphene { namespace chain { } } -FC_REFLECT_DERIVED( graphene::chain::tournament_object, (graphene::db::object), - (options) - (start_time) - (end_time) ) - +FC_REFLECT_DERIVED(graphene::chain::tournament_details_object, (graphene::db::object), + (registered_players) + (payers)) +FC_REFLECT_DERIVED(graphene::chain::tournament_object, (graphene::db::object), + (creator) + (options) + (start_time) + (end_time) + (prize_pool) + (tournament_details_id)) diff --git a/libraries/chain/tournament_evaluator.cpp b/libraries/chain/tournament_evaluator.cpp index c2c41fdb..0b8d96fe 100644 --- a/libraries/chain/tournament_evaluator.cpp +++ b/libraries/chain/tournament_evaluator.cpp @@ -84,43 +84,65 @@ namespace graphene { namespace chain { void_result tournament_join_evaluator::do_evaluate( const tournament_join_operation& op ) { try { const database& d = db(); - const tournament_object& t = op.tournament_id(d); - const account_object& payer_account = op.payer_account_id(d); - const account_object& player_account = op.player_account_id(d); - const asset_object& buy_in_asset_type = op.buy_in.asset_id(d); + _tournament_obj = &op.tournament_id(d); + _tournament_details_obj = &_tournament_obj->tournament_details_id(d); + _payer_account = &op.payer_account_id(d); + //const account_object& player_account = op.player_account_id(d); + _buy_in_asset_type = &op.buy_in.asset_id(d); - FC_ASSERT(t.registered_players.find(op.player_account_id) == t.registered_players.end(), + FC_ASSERT(_tournament_details_obj->registered_players.size() < _tournament_obj->options.number_of_players, + "Tournament is already full"); + FC_ASSERT(d.head_block_time() <= _tournament_obj->options.registration_deadline, + "Registration deadline has already passed"); + + FC_ASSERT(_tournament_obj->options.whitelist.empty() || + _tournament_obj->options.whitelist.find(op.player_account_id) == _tournament_obj->options.whitelist.end(), + "Player is not on the whitelist for this tournament"); + + FC_ASSERT(_tournament_details_obj->registered_players.find(op.player_account_id) == _tournament_details_obj->registered_players.end(), "Player is already registered for this tournament"); - FC_ASSERT(op.buy_in == t.options.buy_in, "Buy-in is incorrect"); + FC_ASSERT(op.buy_in == _tournament_obj->options.buy_in, "Buy-in is incorrect"); - GRAPHENE_ASSERT(!buy_in_asset_type.is_transfer_restricted(), + GRAPHENE_ASSERT(!_buy_in_asset_type->is_transfer_restricted(), transfer_restricted_transfer_asset, "Asset {asset} has transfer_restricted flag enabled", ("asset", op.buy_in.asset_id)); - GRAPHENE_ASSERT(is_authorized_asset(d, payer_account, buy_in_asset_type), + GRAPHENE_ASSERT(is_authorized_asset(d, *_payer_account, *_buy_in_asset_type), transfer_from_account_not_whitelisted, "payer account ${payer} is not whitelisted for asset ${asset}", ("payer", op.payer_account_id) ("asset", op.buy_in.asset_id)); - bool sufficient_balance = d.get_balance(payer_account, buy_in_asset_type).amount >= op.buy_in.amount; + bool sufficient_balance = d.get_balance(*_payer_account, *_buy_in_asset_type).amount >= op.buy_in.amount; FC_ASSERT(sufficient_balance, "Insufficient Balance: paying account '${payer}' has insufficient balance to pay buy-in of ${buy_in} (balance is ${balance})", - ("payer", payer_account.name) + ("payer", _payer_account->name) ("buy_in", d.to_pretty_string(op.buy_in)) - ("balance",d.to_pretty_string(d.get_balance(payer_account, buy_in_asset_type)))); + ("balance",d.to_pretty_string(d.get_balance(*_payer_account, *_buy_in_asset_type)))); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } void_result tournament_join_evaluator::do_apply( const tournament_join_operation& op ) { try { - const database& d = db(); - const tournament_object& t = op.tournament_id(d); + bool start_tournament = _tournament_details_obj->registered_players.size() + 1 == _tournament_obj->options.number_of_players; + db().adjust_balance(op.payer_account_id, -op.buy_in); - db().modify(t, [&](tournament_object& tournament_obj){ - tournament_obj.payers[op.payer_account_id] += op.buy_in.amount; - tournament_obj.registered_players.insert(op.player_account_id); + db().modify(*_tournament_details_obj, [&](tournament_details_object& tournament_details_obj){ + tournament_details_obj.payers[op.payer_account_id] += op.buy_in.amount; + tournament_details_obj.registered_players.insert(op.player_account_id); + }); + db().modify(*_tournament_obj, [&](tournament_object& tournament_obj){ + ++tournament_obj.registered_players; + tournament_obj.prize_pool += op.buy_in.amount; + if (start_tournament) + { + if (tournament_obj.options.start_time) + tournament_obj.start_time = tournament_obj.options.start_time; + else + tournament_obj.start_time = db().head_block_time() + fc::seconds(*tournament_obj.options.start_delay); + + } }); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) }