More validation of tournament_join op
This commit is contained in:
parent
234a76fdd1
commit
4e856996be
4 changed files with 86 additions and 28 deletions
|
|
@ -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<char, GRAPHENE_MAX_ASSET_SYMBOL_LENGTH> 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, )
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ namespace graphene { namespace chain {
|
|||
|
||||
class tournament_join_evaluator : public evaluator<tournament_join_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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<tournament_details_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<account_id_type> registered_players;
|
||||
|
||||
/// List of payers who have contributed to the prize pool
|
||||
flat_map<account_id_type, share_type> payers;
|
||||
};
|
||||
|
||||
class tournament_object : public graphene::db::abstract_object<tournament_object>
|
||||
{
|
||||
public:
|
||||
|
|
@ -24,16 +40,21 @@ namespace graphene { namespace chain {
|
|||
/// If the tournament has ended, the time it ended
|
||||
optional<time_point_sec> end_time;
|
||||
|
||||
/// List of players registered for this tournament
|
||||
flat_set<account_id_type> 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<account_id_type, share_type> 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))
|
||||
|
|
|
|||
|
|
@ -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) ) }
|
||||
|
|
|
|||
Loading…
Reference in a new issue