diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index a2ac6423..fde80782 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -540,6 +540,7 @@ void database::_apply_block( const signed_block& next_block ) clear_expired_orders(); update_expired_feeds(); update_withdraw_permissions(); + update_tournaments(); // n.b., update_maintenance_flag() happens this late // because get_slot_time() / get_slot_at_time() is needed above diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 48f38027..0198bd0a 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -172,6 +173,8 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -202,6 +205,7 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); //Implementation object indexes add_index< primary_index >(); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index db51fc51..5bb968d7 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -482,7 +482,7 @@ void database::update_tournaments() auto& registration_deadline_index = get_index_type().indices().get(); // 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() && + while (!registration_deadline_index.empty() && registration_deadline_index.begin()->get_state() == tournament_state::accepting_registrations && registration_deadline_index.begin()->options.registration_deadline <= head_block_time()) { diff --git a/libraries/chain/include/graphene/chain/protocol/tournament.hpp b/libraries/chain/include/graphene/chain/protocol/tournament.hpp index 36636142..2da7d2ed 100644 --- a/libraries/chain/include/graphene/chain/protocol/tournament.hpp +++ b/libraries/chain/include/graphene/chain/protocol/tournament.hpp @@ -162,6 +162,7 @@ FC_REFLECT( graphene::chain::tournament_options, (start_delay) (round_delay) (number_of_wins) + (meta) (game_options)) FC_REFLECT( graphene::chain::tournament_create_operation, (fee) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 469f6e37..4e7e4852 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -135,6 +135,7 @@ namespace graphene { namespace chain { worker_object_type, balance_object_type, tournament_object_type, + tournament_details_object_type, match_object_type, game_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types @@ -158,8 +159,7 @@ namespace graphene { namespace chain { impl_budget_record_object_type, impl_special_authority_object_type, impl_buyback_object_type, - impl_fba_accumulator_object_type, - impl_tournament_details_object_type + impl_fba_accumulator_object_type }; //typedef fc::unsigned_int object_id_type; @@ -180,6 +180,7 @@ namespace graphene { namespace chain { class balance_object; class blinded_balance_object; class tournament_object; + class tournament_details_object; class match_object; class game_object; @@ -198,6 +199,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, worker_object_type, worker_object> worker_id_type; typedef object_id< protocol_ids, balance_object_type, balance_object> balance_id_type; typedef object_id< protocol_ids, tournament_object_type, tournament_object> tournament_id_type; + typedef object_id< protocol_ids, tournament_details_object_type, tournament_details_object> tournament_details_id_type; typedef object_id< protocol_ids, match_object_type, match_object> match_id_type; typedef object_id< protocol_ids, game_object_type, game_object> game_id_type; @@ -238,7 +240,6 @@ 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; @@ -354,6 +355,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (worker_object_type) (balance_object_type) (tournament_object_type) + (tournament_details_object_type) (match_object_type) (game_object_type) (OBJECT_TYPE_COUNT) @@ -376,7 +378,6 @@ 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 ) diff --git a/libraries/chain/include/graphene/chain/tournament_object.hpp b/libraries/chain/include/graphene/chain/tournament_object.hpp index 9923a5c6..2b58cb66 100644 --- a/libraries/chain/include/graphene/chain/tournament_object.hpp +++ b/libraries/chain/include/graphene/chain/tournament_object.hpp @@ -3,6 +3,8 @@ #include #include #include +#include + namespace graphene { namespace chain { class database; using namespace graphene::db; @@ -14,7 +16,7 @@ namespace graphene { namespace chain { { public: static const uint8_t space_id = protocol_ids; - static const uint8_t type_id = impl_tournament_details_object_type; + static const uint8_t type_id = tournament_details_object_type; /// List of players registered for this tournament flat_set registered_players; @@ -74,6 +76,18 @@ namespace graphene { namespace chain { time_point_sec get_registration_deadline() const { return options.registration_deadline; } + // serialization functions: + // for serializing to raw, go through a temporary sstream object to avoid + // having to implement serialization in the header file + template + friend Stream& operator<<( Stream& s, const tournament_object& tournament_obj ); + + template + friend Stream& operator>>( Stream& s, tournament_object& tournament_obj ); + + void pack_impl(std::ostream& stream) const; + void unpack_impl(std::istream& stream); + /// 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); @@ -128,18 +142,66 @@ namespace graphene { namespace chain { > tournament_object_multi_index_type; typedef generic_index tournament_index; + typedef multi_index_container< + tournament_details_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > > > + > tournament_details_object_multi_index_type; + typedef generic_index tournament_details_index; + + template + inline Stream& operator<<( Stream& s, const tournament_object& tournament_obj ) + { + fc_elog(fc::logger::get("tournament"), "In tournament_obj to_raw"); + // pack all fields exposed in the header in the usual way + // instead of calling the derived pack, just serialize the one field in the base class + // fc::raw::pack >(s, tournament_obj); + fc::raw::pack(s, tournament_obj.id); + fc::raw::pack(s, tournament_obj.creator); + fc::raw::pack(s, tournament_obj.options); + fc::raw::pack(s, tournament_obj.start_time); + fc::raw::pack(s, tournament_obj.end_time); + fc::raw::pack(s, tournament_obj.prize_pool); + fc::raw::pack(s, tournament_obj.registered_players); + fc::raw::pack(s, tournament_obj.tournament_details_id); + + // fc::raw::pack the contents hidden in the impl class + std::ostringstream stream; + tournament_obj.pack_impl(stream); + fc::raw::pack(s, stream.str()); + + return s; + } + template + inline Stream& operator>>( Stream& s, tournament_object& tournament_obj ) + { + fc_elog(fc::logger::get("tournament"), "In tournament_obj from_raw"); + // unpack all fields exposed in the header in the usual way + //fc::raw::unpack >(s, tournament_obj); + fc::raw::unpack(s, tournament_obj.id); + fc::raw::unpack(s, tournament_obj.creator); + fc::raw::unpack(s, tournament_obj.options); + fc::raw::unpack(s, tournament_obj.start_time); + fc::raw::unpack(s, tournament_obj.end_time); + fc::raw::unpack(s, tournament_obj.prize_pool); + fc::raw::unpack(s, tournament_obj.registered_players); + fc::raw::unpack(s, tournament_obj.tournament_details_id); + + // fc::raw::unpack the contents hidden in the impl class + std::string stringified_stream; + fc::raw::unpack(s, stringified_stream); + std::istringstream stream(stringified_stream); + tournament_obj.unpack_impl(stream); + + return s; + } + } } 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)) +FC_REFLECT_TYPENAME(graphene::chain::tournament_object) // manually serialized FC_REFLECT_ENUM(graphene::chain::tournament_state, (accepting_registrations) (awaiting_start) @@ -147,3 +209,41 @@ FC_REFLECT_ENUM(graphene::chain::tournament_state, (registration_period_expired) (concluded)) +namespace fc { + // Manually reflect tournament_object to variant to properly reflect "state" + inline void to_variant(const graphene::chain::tournament_object& tournament_obj, fc::variant& v) + { + fc_elog(fc::logger::get("tournament"), "In tournament_obj to_variant"); + elog("In tournament_obj to_variant"); + fc::mutable_variant_object o; + o("id", tournament_obj.id) + ("creator", tournament_obj.creator) + ("options", tournament_obj.options) + ("start_time", tournament_obj.start_time) + ("end_time", tournament_obj.end_time) + ("prize_pool", tournament_obj.prize_pool) + ("registered_players", tournament_obj.registered_players) + ("tournament_details_id", tournament_obj.tournament_details_id) + ("state", tournament_obj.get_state()); + + v = o; + } + + // Manually reflect tournament_object to variant to properly reflect "state" + inline void from_variant(const fc::variant& v, graphene::chain::tournament_object& tournament_obj) + { + fc_elog(fc::logger::get("tournament"), "In tournament_obj from_variant"); + tournament_obj.id = v["id"].as(); + tournament_obj.creator = v["creator"].as(); + tournament_obj.options = v["options"].as(); + tournament_obj.start_time = v["start_time"].as >(); + tournament_obj.end_time = v["end_time"].as >(); + tournament_obj.prize_pool = v["prize_pool"].as(); + tournament_obj.registered_players = v["registered_players"].as(); + tournament_obj.tournament_details_id = v["tournament_details_id"].as(); + // TODO deserialize "State" + } +} //end namespace fc + + + diff --git a/libraries/chain/tournament_evaluator.cpp b/libraries/chain/tournament_evaluator.cpp index 69f5e36d..0f570cdd 100644 --- a/libraries/chain/tournament_evaluator.cpp +++ b/libraries/chain/tournament_evaluator.cpp @@ -29,7 +29,9 @@ namespace graphene { namespace chain { // TODO: make this committee-set const uint32_t maximum_tournament_whitelist_length = 1000; - 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.empty() || + 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)); @@ -72,66 +74,88 @@ namespace graphene { namespace chain { object_id_type tournament_create_evaluator::do_apply( const tournament_create_operation& op ) { try { - const tournament_details_object& tournament_details = - db().create( [&]( tournament_details_object& a ) { - }); + const tournament_details_object& tournament_details = + db().create( [&]( tournament_details_object& a ) { + }); - const tournament_object& new_tournament = - db().create( [&]( tournament_object& t ) { - t.options = op.options; - t.creator = op.creator; - t.tournament_details_id = tournament_details.id; + const tournament_object& new_tournament = + db().create( [&]( tournament_object& t ) { + t.options = op.options; + t.creator = op.creator; + t.tournament_details_id = tournament_details.id; }); - return new_tournament.id; + + fc_ilog(fc::logger::get("tournament"), + "Created tournament ${id} with details id ${details_id}", + ("id", new_tournament.id)("details_id", tournament_details.id)); + return new_tournament.id; } FC_CAPTURE_AND_RETHROW( (op) ) } void_result tournament_join_evaluator::do_evaluate( const tournament_join_operation& op ) { try { + fc_ilog(fc::logger::get("tournament"), ".",); const database& d = db(); + fc_ilog(fc::logger::get("tournament"), ".",); _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_ilog(fc::logger::get("tournament"), ".",); _payer_account = &op.payer_account_id(d); + fc_ilog(fc::logger::get("tournament"), ".",); //const account_object& player_account = op.player_account_id(d); _buy_in_asset_type = &op.buy_in.asset_id(d); + fc_ilog(fc::logger::get("tournament"), ".",); // TODO 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_ilog(fc::logger::get("tournament"), ".",); FC_ASSERT(d.head_block_time() <= _tournament_obj->options.registration_deadline, "Registration deadline has already passed"); + fc_ilog(fc::logger::get("tournament"), ".",); 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_ilog(fc::logger::get("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_ilog(fc::logger::get("tournament"), ".",); FC_ASSERT(op.buy_in == _tournament_obj->options.buy_in, "Buy-in is incorrect"); + fc_ilog(fc::logger::get("tournament"), ".",); 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)); + fc_ilog(fc::logger::get("tournament"), ".",); 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)); + fc_ilog(fc::logger::get("tournament"), ".",); bool sufficient_balance = d.get_balance(*_payer_account, *_buy_in_asset_type).amount >= op.buy_in.amount; + fc_ilog(fc::logger::get("tournament"), ".",); 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) ("buy_in", d.to_pretty_string(op.buy_in)) ("balance",d.to_pretty_string(d.get_balance(*_payer_account, *_buy_in_asset_type)))); + fc_ilog(fc::logger::get("tournament"), ".",); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } void_result tournament_join_evaluator::do_apply( const tournament_join_operation& op ) { try { + fc_ilog(fc::logger::get("tournament"), "in do_apply",); db().modify(*_tournament_obj, [&](tournament_object& tournament_obj){ + fc_ilog(fc::logger::get("tournament"), "in do_apply's modify",); tournament_obj.on_player_registered(db(), op.payer_account_id, op.player_account_id); + fc_ilog(fc::logger::get("tournament"), "in do_apply's modify after event",); }); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index 107ebbef..adbca09f 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -29,6 +29,8 @@ #include +#include + #include #include @@ -67,11 +69,14 @@ void witness_plugin::plugin_set_program_options( { auto default_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("nathan"))); string witness_id_example = fc::json::to_string(chain::witness_id_type(5)); + string witness_id_example2 = fc::json::to_string(chain::witness_id_type(6)); command_line_options.add_options() ("enable-stale-production", bpo::bool_switch()->notifier([this](bool e){_production_enabled = e;}), "Enable block production, even if the chain is stale.") ("required-participation", bpo::bool_switch()->notifier([this](int e){_required_witness_participation = uint32_t(e*GRAPHENE_1_PERCENT);}), "Percent of witnesses (0-99) that must be participating in order to produce blocks") ("witness-id,w", bpo::value>()->composing()->multitoken(), ("ID of witness controlled by this node (e.g. " + witness_id_example + ", quotes are required, may specify multiple times)").c_str()) + ("witness-ids,W", bpo::value(), + ("IDs of multiple witnesses controlled by this node (e.g. [" + witness_id_example + ", " + witness_id_example2 + "], quotes are required)").c_str()) ("private-key", bpo::value>()->composing()->multitoken()-> DEFAULT_VALUE_VECTOR(std::make_pair(chain::public_key_type(default_priv_key.get_public_key()), graphene::utilities::key_to_wif(default_priv_key))), "Tuple of [PublicKey, WIF private key] (may specify multiple times)") @@ -89,6 +94,8 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m ilog("witness plugin: plugin_initialize() begin"); _options = &options; LOAD_VALUE_SET(options, "witness-id", _witnesses, chain::witness_id_type) + if (options.count("witness-ids")) + boost::insert(_witnesses, fc::json::from_string(options.at("witness-ids").as()).as>()); if( options.count("private-key") ) { diff --git a/libraries/wallet/include/graphene/wallet/reflect_util.hpp b/libraries/wallet/include/graphene/wallet/reflect_util.hpp index 497303c5..8ffe765e 100644 --- a/libraries/wallet/include/graphene/wallet/reflect_util.hpp +++ b/libraries/wallet/include/graphene/wallet/reflect_util.hpp @@ -62,7 +62,7 @@ struct static_variant_map_visitor template< typename T > result_type operator()( const T& dummy ) { - assert( which == m.which_to_name.size() ); + assert( which == (int)m.which_to_name.size() ); std::string name = clean_name( fc::get_typename::name() ); m.name_to_which[ name ] = which; m.which_to_name.push_back( name ); diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 3d44a4d9..6d0f3856 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1607,4 +1607,5 @@ FC_API( graphene::wallet::wallet_api, (blind_history) (receive_blind_transfer) (tournament_create) + (tournament_join) )