Implementing missing functionality

Peerplays Blockchain pre-launch settings & modifications I II III

Merge branch 'rock-paper-scissors' of http://syncad.storm.pl:56780/blocktrades/graphene into rock-paper-scissors-ro
This commit is contained in:
Roman Olearski 2017-04-07 17:28:53 +02:00
commit 33e2f4fd14
19 changed files with 343 additions and 178358 deletions

178331
genesis.json

File diff suppressed because it is too large Load diff

View file

@ -218,6 +218,11 @@ struct get_impacted_account_visitor
_impacted.insert( op.payer_account_id );
_impacted.insert( op.player_account_id );
}
void operator()( const tournament_leave_operation& op )
{
_impacted.erase( op.payer_account_id );
_impacted.erase( op.player_account_id );
}
void operator()( const game_move_operation& op )
{
_impacted.insert( op.player_account_id );

View file

@ -186,3 +186,4 @@
#define TOURNAMENT_MINIMAL_RAKE_FEE_PERCENTAGE (1*GRAPHENE_1_PERCENT)
#define TOURNAMENT_MAXIMAL_RAKE_FEE_PERCENTAGE (20*GRAPHENE_1_PERCENT)
#define TOURNAMENT_MAXIMAL_REGISTRATION_DEADLINE (60*60*24*30) // seconds, 30 days
#define TOURNAMENT_MAX_NUMBER_OF_WINS 100

View file

@ -98,7 +98,8 @@ namespace graphene { namespace chain {
game_move_operation,
asset_update_dividend_operation,
asset_dividend_distribution_operation, // VIRTUAL
tournament_payout_operation // VIRTUAL
tournament_payout_operation, // VIRTUAL
tournament_leave_operation
> operation;
/// @} // operations group

View file

@ -145,6 +145,30 @@ namespace graphene { namespace chain {
void validate()const;
};
struct tournament_leave_operation : public base_operation
{
struct fee_parameters_type {
share_type fee = GRAPHENE_BLOCKCHAIN_PRECISION;
};
asset fee;
/// The account that payed the buy-in for the tournament
account_id_type payer_account_id;
/// The account that would play in the tournament, would receive any winnings.
account_id_type player_account_id;
/// The tournament `player_account_id` is leaving
tournament_id_type tournament_id;
extensions_type extensions;
account_id_type fee_payer()const { return payer_account_id; }
share_type calculate_fee(const fee_parameters_type& k)const;
void validate()const;
};
typedef fc::static_variant<rock_paper_scissors_throw_commit, rock_paper_scissors_throw_reveal> game_specific_moves;
struct game_move_operation : public base_operation
@ -227,6 +251,12 @@ FC_REFLECT( graphene::chain::tournament_join_operation,
(tournament_id)
(buy_in)
(extensions))
FC_REFLECT( graphene::chain::tournament_leave_operation,
(fee)
(payer_account_id)
(player_account_id)
(tournament_id)
(extensions))
FC_REFLECT( graphene::chain::game_move_operation,
(fee)
(game_id)
@ -243,6 +273,7 @@ FC_REFLECT( graphene::chain::tournament_payout_operation,
FC_REFLECT( graphene::chain::tournament_create_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::tournament_join_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::tournament_leave_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::game_move_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::tournament_payout_operation::fee_parameters_type, )

View file

@ -28,6 +28,21 @@ namespace graphene { namespace chain {
void_result do_apply( const tournament_join_operation& o );
};
class tournament_leave_evaluator : public evaluator<tournament_leave_evaluator>
{
private:
const tournament_object* _tournament_obj = nullptr;
const tournament_details_object* _tournament_details_obj = nullptr;
//const account_object* _payer_account = nullptr;
//const account_object* _player_account = nullptr;
//const asset_object* _buy_in_back_asset_type = nullptr;
public:
typedef tournament_leave_operation operation_type;
void_result do_evaluate( const tournament_leave_operation& o );
void_result do_apply( const tournament_leave_operation& o );
};
class game_move_evaluator : public evaluator<game_move_evaluator>
{
private:

View file

@ -113,6 +113,7 @@ namespace graphene { namespace chain {
/// called by database maintenance code when registration for this contest has expired
void on_registration_deadline_passed(database& db);
void on_player_registered(database& db, account_id_type payer_id, account_id_type player_id);
void on_player_unregistered(database& db, account_id_type payer_id, account_id_type player_id);
void on_start_time_arrived(database& db);
void on_match_completed(database& db, const match_object& match);

View file

@ -52,6 +52,11 @@ void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_o
if( _sell_asset->options.blacklist_markets.size() )
FC_ASSERT( _sell_asset->options.blacklist_markets.find(_receive_asset->id) == _sell_asset->options.blacklist_markets.end() );
// $$$ I. DEX Task The Peerplays DEX should only allow UIA and sidechain assets to be paired (traded) with the core token (PPY)
FC_ASSERT(_receive_asset->id == asset_id_type() || _sell_asset->id == asset_id_type(),
"No asset in the trade is CORE.");
FC_ASSERT( is_authorized_asset( d, *_seller, *_sell_asset ) );
FC_ASSERT( is_authorized_asset( d, *_seller, *_receive_asset ) );

View file

@ -75,7 +75,6 @@ namespace graphene { namespace chain {
void on_entry(const initiate_match& event, match_state_machine_& fsm)
{
match_object& match = *fsm.match_obj;
fc_ilog(fc::logger::get("tournament"),
"Match ${id} is now in progress",
("id", match.id));
@ -89,7 +88,9 @@ namespace graphene { namespace chain {
{
void on_entry(const game_complete& event, match_state_machine_& fsm)
{
match_object& match = *fsm.match_obj;
//wdump((match));
fc_ilog(fc::logger::get("tournament"),
"Match ${id} is complete",
("id", match.id));
@ -124,16 +125,20 @@ namespace graphene { namespace chain {
}
else
{
match.match_winners.insert(match.players[event.db.get_random_bits(match.players.size())]);
}
// $$$ III. Rock Paper Scissors Game Need to review how Ties are dealt with.
short i = std::rand() % match.players.size(); // ! event.db.get_random_bits(match.players.size()) ;
match.match_winners.insert(match.players[i]);
++match.number_of_wins[i];
if (match.number_of_ties == match.games.size())
match.game_winners[match.game_winners.size()-1].insert(match.players[i]);
}
match.end_time = event.db.head_block_time();
const tournament_object& tournament_obj = match.tournament_id(event.db);
event.db.modify(tournament_obj, [&](tournament_object& tournament) {
tournament.on_match_completed(event.db, match);
});
}
void on_entry(const initiate_match& event, match_state_machine_& fsm)
{
@ -238,7 +243,8 @@ namespace graphene { namespace chain {
};
match_object::match_object() :
my(new impl(this))
number_of_ties(0),
my(new impl(this))
{
}

View file

@ -52,6 +52,17 @@ void tournament_join_operation::validate()const
FC_ASSERT( fee.amount >= 0 );
}
share_type tournament_leave_operation::calculate_fee(const fee_parameters_type& k)const
{
return k.fee;
}
void tournament_leave_operation::validate()const
{
FC_ASSERT( fee.amount >= 0 );
}
share_type game_move_operation::calculate_fee(const fee_parameters_type& k)const
{
return k.fee;

View file

@ -57,7 +57,7 @@ namespace graphene { namespace chain {
FC_THROW("Must specify either a fixed start time or a delay");
// TODO: make this committee-set
const uint32_t maximum_tournament_number_of_wins = 100;
const uint32_t maximum_tournament_number_of_wins = TOURNAMENT_MAX_NUMBER_OF_WINS;
FC_ASSERT(op.options.number_of_wins > 0);
FC_ASSERT(op.options.number_of_wins <= maximum_tournament_number_of_wins,
"Matches may not require more than ${number_of_wins} wins",
@ -176,6 +176,48 @@ namespace graphene { namespace chain {
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result tournament_leave_evaluator::do_evaluate( const tournament_leave_operation& op )
{
try {
const database& d = db();
_tournament_obj = &op.tournament_id(d);
fc_ilog(fc::logger::get("tournament"), "details_id = ${id}",("id", _tournament_obj->tournament_details_id));
_tournament_details_obj = &_tournament_obj->tournament_details_id(d);
FC_ASSERT(_tournament_details_obj->registered_players.find(op.player_account_id) != _tournament_details_obj->registered_players.end(),
"Player is not registered for this tournament");
FC_ASSERT(_tournament_details_obj->payers.find(op.payer_account_id) != _tournament_details_obj->payers.end(),
"Payer is not registered for this tournament");
#if 0
_payer_account = &op.payer_account_id(d);
_buy_in_back_asset_type = &(_tournament_obj->options.buy_in.asset_id(d));
GRAPHENE_ASSERT(!_buy_in_back_asset_type->is_transfer_restricted(),
transfer_restricted_transfer_asset,
"Asset {asset} has transfer_restricted flag enabled",
("asset", _buy_in_back_asset_type->id));
GRAPHENE_ASSERT(is_authorized_asset(d, *_payer_account, *_buy_in_back_asset_type),
transfer_from_account_not_whitelisted,
"payer account ${payer} is not whitelisted for asset ${asset}",
("payer", op.payer_account_id)
("asset", _buy_in_back_asset_type->id));
#endif
FC_ASSERT(_tournament_obj->get_state() == tournament_state::accepting_registrations);
FC_ASSERT(d.head_block_time() <= _tournament_obj->options.registration_deadline,
"Registration deadline has already passed");
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result tournament_leave_evaluator::do_apply( const tournament_leave_operation& op )
{ try {
#if 1
db().modify(*_tournament_obj, [&](tournament_object& tournament_obj){
tournament_obj.on_player_unregistered(db(), op.payer_account_id, op.player_account_id);
});
#endif
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result game_move_evaluator::do_evaluate( const game_move_operation& o )
{ try {
const database& d = db();
@ -184,6 +226,7 @@ namespace graphene { namespace chain {
return void_result();
} FC_CAPTURE_AND_RETHROW( (o) ) }
void_result game_move_evaluator::do_apply( const game_move_operation& o )
{ try {
db().modify(*_game_obj, [&](game_object& game_obj){

View file

@ -48,7 +48,16 @@ namespace graphene { namespace chain {
db(db), payer_id(payer_id), player_id(player_id)
{}
};
struct registration_deadline_passed
struct player_unregistered
{
database& db;
account_id_type payer_id;
account_id_type player_id;
player_unregistered(database& db, account_id_type payer_id, account_id_type player_id) :
db(db), payer_id(payer_id), player_id(player_id)
{}
};
struct registration_deadline_passed
{
database& db;
registration_deadline_passed(database& db) : db(db) {};
@ -234,7 +243,7 @@ namespace graphene { namespace chain {
event.db.modify(next_round_match, [&](match_object& next_match_obj) {
if (!event.match.match_winners.empty()) // if there is a winner
if (!event.match.match_winners.empty()) // if there is a winner
{
if (winner_index_in_next_match == 0)
next_match_obj.players.insert(next_match_obj.players.begin(), *event.match.match_winners.begin());
@ -387,14 +396,34 @@ namespace graphene { namespace chain {
tournament_obj->prize_pool += tournament_obj->options.buy_in.amount;
}
void unregister_player(const player_unregistered& event)
{
fc_ilog(fc::logger::get("tournament"),
"In register_player action, player_id is ${player_id}, payer_id is ${payer_id}",
("player_id", event.player_id)("payer_id", event.payer_id));
event.db.adjust_balance(event.payer_id, tournament_obj->options.buy_in);
const tournament_details_object& tournament_details_obj = tournament_obj->tournament_details_id(event.db);
event.db.modify(tournament_details_obj, [&](tournament_details_object& tournament_details_obj){
tournament_details_obj.payers[event.payer_id] -= tournament_obj->options.buy_in.amount;
if (tournament_details_obj.payers[event.payer_id] <= 0)
tournament_details_obj.payers.erase(event.payer_id);
tournament_details_obj.registered_players.erase(event.player_id);
});
++tournament_obj->registered_players;
tournament_obj->prize_pool += tournament_obj->options.buy_in.amount;
}
// Transition table for tournament
struct transition_table : mpl::vector<
// Start Event Next Action Guard
// +---------------------------+-----------------------------+----------------------------+---------------------+----------------------+
a_row < accepting_registrations, player_registered, accepting_registrations, &x::register_player >,
a_row < accepting_registrations, player_unregistered, accepting_registrations, &x::unregister_player >,
row < accepting_registrations, player_registered, awaiting_start, &x::register_player, &x::will_be_fully_registered >,
_row < accepting_registrations, registration_deadline_passed, registration_period_expired >,
// +---------------------------+-----------------------------+----------------------------+---------------------+----------------------+
a_row < awaiting_start, player_unregistered, accepting_registrations, &x::unregister_player >,
_row < awaiting_start, start_time_arrived, in_progress >,
// +---------------------------+-----------------------------+----------------------------+---------------------+----------------------+
_row < in_progress, match_completed, in_progress >,
@ -519,6 +548,11 @@ namespace graphene { namespace chain {
my->state_machine.process_event(player_registered(db, payer_id, player_id));
}
void tournament_object::on_player_unregistered(database& db, account_id_type payer_id, account_id_type player_id)
{
my->state_machine.process_event(player_unregistered(db, payer_id, player_id));
}
void tournament_object::on_start_time_arrived(database& db)
{
my->state_machine.process_event(start_time_arrived(db));

@ -1 +1 @@
Subproject commit 15f0dfe583b099955b1102555854e9a0e0925067
Subproject commit c1f098e14a9f1d4e31b539b63265ffe575240d10

View file

@ -50,7 +50,7 @@ void generate_genesis_plugin::plugin_set_program_options(
command_line_options.add_options()
("output-genesis-file,o", bpo::value<std::string>()->default_value("genesis.json"), "Genesis file to create")
("output-csvlog-file,o", bpo::value<std::string>()->default_value("log.csv"), "CSV log file to create")
("snapshot-block-number", bpo::value<uint32_t>()->default_value(0), "Block number at which to snapshot balances")
("snapshot-block-number", bpo::value<uint32_t>(), "Block number at which to snapshot balances")
;
config_file_options.add(command_line_options);
}
@ -67,32 +67,33 @@ void generate_genesis_plugin::plugin_initialize(const boost::program_options::va
_genesis_filename = options["output-genesis-file"].as<std::string>();
_csvlog_filename = options["output-csvlog-file"].as<std::string>();
_block_to_snapshot = options["snapshot-block-number"].as<uint32_t>();
if (options.count("snapshot-block-number"))
_block_to_snapshot = options["snapshot-block-number"].as<uint32_t>();
database().applied_block.connect([this](const graphene::chain::signed_block& b){ block_applied(b); });
ilog("generate genesis plugin: plugin_initialize() end");
} FC_LOG_AND_RETHROW() }
void generate_genesis_plugin::plugin_startup()
{ try {
ilog("generate genesis plugin: plugin_startup() begin");
chain::database& d = database();
if (d.head_block_num() == _block_to_snapshot)
if (_block_to_snapshot)
{
ilog("generate genesis plugin: already at snapshot block");
generate_snapshot();
if (d.head_block_num() == *_block_to_snapshot)
{
ilog("generate genesis plugin: already at snapshot block");
generate_snapshot();
}
else if (d.head_block_num() > *_block_to_snapshot)
elog("generate genesis plugin: already passed snapshot block, you must reindex to return to the snapshot state");
else
elog("generate genesis plugin: waiting for block ${snapshot_block} to generate snapshot, current head is ${head}",
("snapshot_block", _block_to_snapshot)("head", d.head_block_num()));
}
else if (d.head_block_num() > _block_to_snapshot)
elog("generate genesis plugin: already passed snapshot block, you must reindex to return to the snapshot state");
else
elog("generate genesis plugin: waiting for block ${snapshot_block} to generate snapshot, current head is ${head}",
("snapshot_block", _block_to_snapshot)("head", d.head_block_num()));
ilog("generate genesis plugin: plugin_startup() end");
} FC_CAPTURE_AND_RETHROW() }
void generate_genesis_plugin::block_applied(const graphene::chain::signed_block& b)
{
if (b.block_num() == _block_to_snapshot)
if (_block_to_snapshot && b.block_num() == *_block_to_snapshot)
{
ilog("generate genesis plugin: snapshot block has arrived");
generate_snapshot();

View file

@ -52,7 +52,7 @@ private:
boost::program_options::variables_map _options;
uint32_t _block_to_snapshot;
fc::optional<uint32_t> _block_to_snapshot;
std::string _genesis_filename;
std::string _csvlog_filename;
};

View file

@ -1490,13 +1490,25 @@ class wallet_api
signed_transaction tournament_create( string creator, tournament_options options, bool broadcast = false );
/** Join an existing tournament
* @param paying_account the account that is paying the buy-in and the fee to join the tournament
* @param playing_account the account that will be playing in the tournament
* @param payer_account the account that is paying the buy-in and the fee to join the tournament
* @param player_account the account that will be playing in the tournament
* @param buy_in_amount buy_in to pay
* @param buy_in_asset_symbol buy_in asset
* @param tournament_id the tournament the user wishes to join
* @param broadcast true if you wish to broadcast the transaction
* @return the signed version of the transaction
*/
signed_transaction tournament_join( string payer_account, string player_account, tournament_id_type tournament_id, string buy_in_amount, string buy_in_asset_symbol, bool broadcast = false );
/** Leave an existing tournament
* @param payer_account the account that payed buy-in and the fee to join the tournament
* @param player_account the account that would be playing in the tournament
* @param tournament_id the tournament the user wishes to leave
* @param broadcast true if you wish to broadcast the transaction
* @return the signed version of the transaction
*/
signed_transaction tournament_leave( string payer_account, string player_account, tournament_id_type tournament_id, bool broadcast = false);
/** Get a list of upcoming tournaments
* @param limit the number of tournaments to return
*/

View file

@ -4834,7 +4834,7 @@ signed_transaction wallet_api::tournament_join( string payer_account,
FC_ASSERT( !is_locked() );
account_object payer_account_obj = get_account(payer_account);
account_object player_account_obj = get_account(player_account);
graphene::chain::tournament_object tournament_obj = my->get_object<graphene::chain::tournament_object>(tournament_id);
//graphene::chain::tournament_object tournament_obj = my->get_object<graphene::chain::tournament_object>(tournament_id);
fc::optional<asset_object> buy_in_asset_obj = get_asset(buy_in_asset_symbol);
FC_ASSERT(buy_in_asset_obj, "Could not find asset matching ${asset}", ("asset", buy_in_asset_symbol));
@ -4853,6 +4853,29 @@ signed_transaction wallet_api::tournament_join( string payer_account,
return my->sign_transaction( tx, broadcast );
}
signed_transaction wallet_api::tournament_leave( string payer_account,
string player_account,
tournament_id_type tournament_id,
bool broadcast)
{
FC_ASSERT( !is_locked() );
account_object payer_account_obj = get_account(payer_account);
account_object player_account_obj = get_account(player_account);
//graphene::chain::tournament_object tournament_obj = my->get_object<graphene::chain::tournament_object>(tournament_id);
signed_transaction tx;
tournament_leave_operation op;
op.payer_account_id = payer_account_obj.get_id();
op.player_account_id = player_account_obj.get_id();
op.tournament_id = tournament_id;
tx.operations = {op};
my->set_operation_fees( tx, my->_remote_db->get_global_properties().parameters.current_fees );
tx.validate();
return my->sign_transaction( tx, broadcast );
}
vector<tournament_object> wallet_api::get_upcoming_tournaments(uint32_t limit)
{
return my->_remote_db->get_tournaments_in_state(tournament_state::accepting_registrations, limit);

View file

@ -82,7 +82,7 @@ database_fixture::database_fixture()
genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
genesis_state.initial_active_witnesses = 10;
for( int i = 0; i < genesis_state.initial_active_witnesses; ++i )
for( unsigned i = 0; i < genesis_state.initial_active_witnesses; ++i )
{
auto name = "init"+fc::to_string(i);
genesis_state.initial_accounts.emplace_back(name,

View file

@ -288,14 +288,15 @@ public:
tx.validate();
tx.set_expiration(db.head_block_time() + fc::seconds( params.block_interval * (params.maintenance_skip_slots + 1) * 3));
df.sign(tx, sig_priv_key);
if (game_obj.get_state() == game_state::expecting_commit_moves) // checking again
if (/*match_obj.match_winners.empty() &&*/ game_obj.get_state() == game_state::expecting_commit_moves) // checking again
PUSH_TX(db, tx);
}
// spaghetti programming
// walking through all tournaments, matches and games and throwing random moves
// optionaly skip generting randomly selected moves
void play_games(unsigned skip_some_commits = 0, unsigned skip_some_reveals = 0)
// every_move_is >= 0 : every game is tie
void play_games(unsigned skip_some_commits = 0, unsigned skip_some_reveals = 0, int every_move_is = -1)
{
//try
//{
@ -325,7 +326,8 @@ public:
auto iter = std::find(game.players.begin(), game.players.end(), player_id);
unsigned player_index = std::distance(game.players.begin(), iter);
if (!rps_details.commit_moves.at(player_index))
rps_throw(game_id, player_id, (rock_paper_scissors_gesture) (std::rand() % game_options.number_of_gestures), players_keys[player_id]);
rps_throw(game_id, player_id,
(rock_paper_scissors_gesture) (every_move_is >= 0 ? every_move_is : (std::rand() % game_options.number_of_gestures)), players_keys[player_id]);
}
}
}
@ -414,6 +416,7 @@ private:
}
};
#if 1
// Test of basic functionality creating two tournamenst, joinig players,
// playing tournaments to completion, distributing prize.
// Testing of "bye" matches handling can be performed if "bye" matches fix is available.
@ -594,6 +597,120 @@ BOOST_FIXTURE_TEST_CASE( simple, database_fixture )
throw;
}
}
#endif
// Test of handling ties, creating two tournamenst, joinig players,
// All generated moves are identical.
BOOST_FIXTURE_TEST_CASE( ties, database_fixture )
{
try
{
#ifdef BYE_MATCHES_FIXED
#define TEST1_NR_OF_PLAYERS_NUMBER 3
#define TEST2_NR_OF_PLAYERS_NUMBER 5
#else
#define TEST1_NR_OF_PLAYERS_NUMBER 2
#define TEST2_NR_OF_PLAYERS_NUMBER 4
#endif
BOOST_TEST_MESSAGE("Hello ties tournament test");
ACTORS((nathan)(alice)(bob)(carol)(dave)(ed)(frank)(george)(harry)(ike));
tournaments_helper tournament_helper(*this);
fc::ecc::private_key nathan_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan")));
BOOST_TEST_MESSAGE( "Giving folks some money" );
transfer(committee_account, nathan_id, asset(1000000000));
transfer(committee_account, alice_id, asset(2000000));
transfer(committee_account, bob_id, asset(3000000));
transfer(committee_account, carol_id, asset(4000000));
transfer(committee_account, dave_id, asset(5000000));
transfer(committee_account, ed_id, asset(6000000));
BOOST_TEST_MESSAGE( "Preparing nathan" );
upgrade_to_lifetime_member(nathan);
BOOST_CHECK(nathan.is_lifetime_member());
uint16_t tournaments_to_complete = 0;
asset buy_in = asset(12000);
tournament_id_type tournament_id;
BOOST_TEST_MESSAGE( "Preparing a tournament, insurance disabled" );
tournament_id = tournament_helper.create_tournament (nathan_id, nathan_priv_key, buy_in, TEST1_NR_OF_PLAYERS_NUMBER, 30, 30);
BOOST_REQUIRE(tournament_id == tournament_id_type());
tournament_helper.join_tournament(tournament_id, alice_id, alice_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("alice"))), buy_in);
tournament_helper.join_tournament(tournament_id, bob_id, bob_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("bob"))), buy_in);
#if TEST1_NR_OF_PLAYERS_NUMBER > 2
tournament_helper.join_tournament(tournament_id, carol_id, carol_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("carol"))), buy_in);
#endif
++tournaments_to_complete;
BOOST_TEST_MESSAGE( "Preparing another one, insurance enabled" );
buy_in = asset(13000);
tournament_id = tournament_helper.create_tournament (nathan_id, nathan_priv_key, buy_in, TEST2_NR_OF_PLAYERS_NUMBER,
30, 30, 3, 3600, 3, 3, true);
BOOST_REQUIRE(tournament_id == tournament_id_type(1));
tournament_helper.join_tournament(tournament_id, alice_id, alice_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("alice"))), buy_in);
tournament_helper.join_tournament(tournament_id, bob_id, bob_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("bob"))), buy_in);
tournament_helper.join_tournament(tournament_id, carol_id, carol_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("carol"))), buy_in);
tournament_helper.join_tournament(tournament_id, dave_id, dave_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("dave"))), buy_in);
#if TEST2_NR_OF_PLAYERS_NUMBER > 4
tournament_helper.join_tournament(tournament_id, ed_id, ed_id, fc::ecc::private_key::regenerate(fc::sha256::hash(string("ed"))), buy_in);
#endif
++tournaments_to_complete;
std::set<tournament_id_type> tournaments = tournament_helper.list_tournaments();
std::map<account_id_type, std::map<asset_id_type, share_type>> players_balances = tournament_helper.list_players_balances();
uint16_t rake_fee_percentage = db.get_global_properties().parameters.rake_fee_percentage;
BOOST_TEST_MESSAGE( "Generating blocks, waiting for tournaments' completion");
while(tournaments_to_complete > 0)
{
generate_block();
//tournament_helper.play_games(3, 4, 1);
tournament_helper.play_games(0, 0, 1);
for(const auto& tournament_id: tournaments)
{
const tournament_object& tournament = tournament_id(db);
if (tournament.get_state() == tournament_state::concluded) {
const tournament_details_object& tournament_details = tournament.tournament_details_id(db);
const match_object& final_match = (tournament_details.matches[tournament_details.matches.size() - 1])(db);
assert(final_match.match_winners.size() == 1);
const account_id_type& winner_id = *final_match.match_winners.begin();
BOOST_TEST_MESSAGE( "The winner of " + std::string(object_id_type(tournament_id)) + " is " + winner_id(db).name + " " + std::string(object_id_type(winner_id)));
share_type rake_amount = (fc::uint128_t(tournament.prize_pool.value) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100).to_uint64();
optional<account_id_type> dividend_account = tournament_helper.get_asset_dividend_account(tournament.options.buy_in.asset_id);
if (dividend_account.valid())
players_balances[*dividend_account][tournament.options.buy_in.asset_id] += rake_amount; players_balances[winner_id][tournament.options.buy_in.asset_id] += tournament.prize_pool - rake_amount;
tournaments.erase(tournament_id);
--tournaments_to_complete;
break;
}
}
sleep(1);
}
// checking if prizes were distributed correctly
BOOST_CHECK(tournaments.size() == 0);
std::map<account_id_type, std::map<asset_id_type, share_type>> last_players_balances = tournament_helper.list_players_balances();
for (auto a: last_players_balances)
{
BOOST_TEST_MESSAGE( "Checking " + a.first(db).name + "'s balance " + std::to_string((uint64_t)(a.second[asset_id_type()].value)) );
BOOST_CHECK(a.second[asset_id_type()] == players_balances[a.first][asset_id_type()]);
}
BOOST_TEST_MESSAGE("Bye ties tournament test\n");
}
catch (fc::exception& e)
{
edump((e.to_detail_string()));
throw;
}
}
// Test of canceled tournament
// Checking buyin refund.