More work on tournament registration, tournaments are now canceled and
buy-in is refunded
This commit is contained in:
parent
4e856996be
commit
122dbfc698
4 changed files with 95 additions and 5 deletions
|
|
@ -32,6 +32,7 @@
|
|||
#include <graphene/chain/transaction_object.hpp>
|
||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/tournament_object.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||
|
||||
|
|
@ -468,4 +469,55 @@ void database::update_withdraw_permissions()
|
|||
remove(*permit_index.begin());
|
||||
}
|
||||
|
||||
void database::update_tournaments()
|
||||
{
|
||||
// First, cancel any tournaments that didn't get enough players
|
||||
auto& registration_deadline_index = get_index_type<tournament_index>().indices().get<by_registration_deadline>();
|
||||
// this index is sorted on state and deadline, so the tournaments awaiting registrations with the earliest
|
||||
// deadlines will be at the beginning
|
||||
while (registration_deadline_index.empty() &&
|
||||
registration_deadline_index.begin()->state == tournament_state::accepting_registrations &&
|
||||
registration_deadline_index.begin()->options.registration_deadline <= head_block_time())
|
||||
{
|
||||
const tournament_object& tournament_obj = *registration_deadline_index.begin();
|
||||
fc_ilog(fc::logger::get("tournament"),
|
||||
"Canceling tournament ${id} because its deadline expired",
|
||||
("id", tournament_obj.id));
|
||||
// cancel this tournament
|
||||
// repay everyone who paid into the prize pool
|
||||
const tournament_details_object& details = tournament_obj.tournament_details_id(*this);
|
||||
for (const auto& payer_pair : details.payers)
|
||||
{
|
||||
// TODO: create a virtual operation to record the refund
|
||||
// we'll think of this as just releasing an asset that the user had locked up
|
||||
// for a period of time, not as a transfer back to the user; it doesn't matter
|
||||
// if they are currently authorized to transfer this asset, they never really
|
||||
// transferred it in the first place
|
||||
adjust_balance(payer_pair.first, asset(payer_pair.second, tournament_obj.options.buy_in.asset_id));
|
||||
}
|
||||
|
||||
modify(tournament_obj, [&](tournament_object& t) {
|
||||
t.state = tournament_state::registration_period_expired;
|
||||
});
|
||||
}
|
||||
|
||||
// Next, start any tournaments that have enough players and whose start time just arrived
|
||||
auto& start_time_index = get_index_type<tournament_index>().indices().get<by_start_time>();
|
||||
while (1)
|
||||
{
|
||||
// find the first tournament waiting to start; if its start time has arrived, start it
|
||||
auto start_iter = start_time_index.lower_bound(boost::make_tuple(tournament_state::awaiting_start));
|
||||
if (start_iter->state == tournament_state::awaiting_start &&
|
||||
*start_iter->start_time <= head_block_time())
|
||||
{
|
||||
modify(*start_iter, [&](tournament_object& t) {
|
||||
t.state = tournament_state::in_progress;
|
||||
});
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ namespace graphene { namespace chain {
|
|||
void update_expired_feeds();
|
||||
void update_maintenance_flag( bool new_maintenance_flag );
|
||||
void update_withdraw_permissions();
|
||||
void update_tournaments();
|
||||
bool check_for_blackswan( const asset_object& mia, bool enable_black_swan = true );
|
||||
|
||||
///Steps performed only at maintenance intervals
|
||||
|
|
|
|||
|
|
@ -23,6 +23,14 @@ namespace graphene { namespace chain {
|
|||
flat_map<account_id_type, share_type> payers;
|
||||
};
|
||||
|
||||
enum class tournament_state
|
||||
{
|
||||
accepting_registrations,
|
||||
awaiting_start,
|
||||
in_progress,
|
||||
registration_period_expired
|
||||
};
|
||||
|
||||
class tournament_object : public graphene::db::abstract_object<tournament_object>
|
||||
{
|
||||
public:
|
||||
|
|
@ -50,15 +58,30 @@ namespace graphene { namespace chain {
|
|||
/// the GUI having to get the details object)
|
||||
uint32_t registered_players = 0;
|
||||
|
||||
/// The current high-level status of the tournament (whether it is currently running or has been canceled, etc)
|
||||
tournament_state state;
|
||||
|
||||
/// Detailed information on this tournament
|
||||
tournament_details_id_type tournament_details_id;
|
||||
|
||||
time_point_sec get_registration_deadline() const { return options.registration_deadline; }
|
||||
|
||||
};
|
||||
|
||||
struct by_registration_deadline {};
|
||||
struct by_start_time {};
|
||||
typedef multi_index_container<
|
||||
tournament_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >
|
||||
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
||||
ordered_non_unique< tag<by_registration_deadline>,
|
||||
composite_key<tournament_object,
|
||||
member<tournament_object, tournament_state, &tournament_object::state>,
|
||||
const_mem_fun<tournament_object, time_point_sec, &tournament_object::get_registration_deadline> > >,
|
||||
ordered_non_unique< tag<by_start_time>,
|
||||
composite_key<tournament_object,
|
||||
member<tournament_object, tournament_state, &tournament_object::state>,
|
||||
member<tournament_object, optional<time_point_sec>, &tournament_object::start_time> > >
|
||||
>
|
||||
> tournament_object_multi_index_type;
|
||||
typedef generic_index<tournament_object, tournament_object_multi_index_type> tournament_index;
|
||||
|
|
@ -74,4 +97,10 @@ FC_REFLECT_DERIVED(graphene::chain::tournament_object, (graphene::db::object),
|
|||
(start_time)
|
||||
(end_time)
|
||||
(prize_pool)
|
||||
(state)
|
||||
(tournament_details_id))
|
||||
FC_REFLECT_ENUM(graphene::chain::tournament_state,
|
||||
(accepting_registrations)
|
||||
(awaiting_start)
|
||||
(in_progress)
|
||||
(registration_period_expired))
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
// TODO: make this committee-set
|
||||
const uint32_t maximum_tournament_whitelist_length = 1000;
|
||||
FC_ASSERT(op.options.whitelist.size() != 1, "Can't create a tournament for one player");
|
||||
FC_ASSERT(op.options.whitelist.size() >= op.options.number_of_players, "Whitelist must allow enough players to fill the tournament");
|
||||
FC_ASSERT(op.options.whitelist.size() < maximum_tournament_whitelist_length,
|
||||
"Whitelist must not be longer than ${maximum_tournament_whitelist_length}",
|
||||
("maximum_tournament_whitelist_length", maximum_tournament_whitelist_length));
|
||||
|
|
@ -76,6 +76,7 @@ namespace graphene { namespace chain {
|
|||
db().create<tournament_object>( [&]( tournament_object& t ) {
|
||||
t.options = op.options;
|
||||
t.creator = op.creator;
|
||||
t.state = tournament_state::accepting_registrations;
|
||||
// t.dynamic_tournament_data_id = dyn_tournament.id;
|
||||
});
|
||||
return new_tournament.id;
|
||||
|
|
@ -90,6 +91,7 @@ namespace graphene { namespace chain {
|
|||
//const account_object& player_account = op.player_account_id(d);
|
||||
_buy_in_asset_type = &op.buy_in.asset_id(d);
|
||||
|
||||
FC_ASSERT(_tournament_obj->state == tournament_state::accepting_registrations);
|
||||
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,
|
||||
|
|
@ -125,7 +127,11 @@ namespace graphene { namespace chain {
|
|||
|
||||
void_result tournament_join_evaluator::do_apply( const tournament_join_operation& op )
|
||||
{ try {
|
||||
bool start_tournament = _tournament_details_obj->registered_players.size() + 1 == _tournament_obj->options.number_of_players;
|
||||
bool registration_complete = _tournament_details_obj->registered_players.size() + 1 == _tournament_obj->options.number_of_players;
|
||||
if (registration_complete)
|
||||
fc_ilog(fc::logger::get("tournament"),
|
||||
"Tournament ${id} now has enough players registered to begin",
|
||||
("id", _tournament_obj->id));
|
||||
|
||||
db().adjust_balance(op.payer_account_id, -op.buy_in);
|
||||
db().modify(*_tournament_details_obj, [&](tournament_details_object& tournament_details_obj){
|
||||
|
|
@ -135,13 +141,15 @@ namespace graphene { namespace chain {
|
|||
db().modify(*_tournament_obj, [&](tournament_object& tournament_obj){
|
||||
++tournament_obj.registered_players;
|
||||
tournament_obj.prize_pool += op.buy_in.amount;
|
||||
if (start_tournament)
|
||||
if (registration_complete)
|
||||
{
|
||||
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);
|
||||
|
||||
// even if the start time is now, mark it as awaiting; we will promote it to in_progress
|
||||
// in update_tournaments() called at the end of the block
|
||||
tournament_obj.state = tournament_state::awaiting_start;
|
||||
}
|
||||
});
|
||||
return void_result();
|
||||
|
|
|
|||
Loading…
Reference in a new issue