From 61d5f43774c5e7f5fa8582b60f427d65aaab20d8 Mon Sep 17 00:00:00 2001 From: Roman Olearski Date: Mon, 3 Jul 2017 13:30:37 +0200 Subject: [PATCH] removed betting tests to seprarate executable found generate_block(s) after ACTORS macro --- tests/CMakeLists.txt | 4 + tests/betting/betting_tests.cpp | 369 ++++++++++++++++++++++++++++++++ 2 files changed, 373 insertions(+) create mode 100644 tests/betting/betting_tests.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 871f9f6d..db5b4f4d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,4 +29,8 @@ file(GLOB INTENSE_SOURCES "intense/*.cpp") add_executable( intense_test ${INTENSE_SOURCES} ${COMMON_SOURCES} ) target_link_libraries( intense_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +file(GLOB BETTING_TESTS "betting/*.cpp") +add_executable( betting_test ${BETTING_TESTS} ${COMMON_SOURCES} ) +target_link_libraries( betting_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) + add_subdirectory( generate_empty_blocks ) diff --git a/tests/betting/betting_tests.cpp b/tests/betting/betting_tests.cpp new file mode 100644 index 00000000..204f4592 --- /dev/null +++ b/tests/betting/betting_tests.cpp @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include "../common/database_fixture.hpp" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//#include + +using namespace graphene::chain; +using namespace graphene::chain::test; + + +BOOST_FIXTURE_TEST_SUITE( betting_tests, database_fixture ) + +#define CREATE_ICE_HOCKEY_BETTING_MARKET() \ + const sport_object& ice_hockey = create_sport({{"en", "Ice Hockey"}, {"zh_Hans", "冰球"}, {"ja", "アイスホッケー"}}); \ + const competitor_object& capitals = create_competitor({{"en", "Washington Capitals"}, {"zh_Hans", "華盛頓首都隊"}, {"ja", "ワシントン・キャピタルズ"}}, ice_hockey.id); \ + const competitor_object& blackhawks = create_competitor({{"en", "Chicago Blackhawks"}, {"zh_Hans", "芝加哥黑鷹"}, {"ja", "シカゴ・ブラックホークス"}}, ice_hockey.id); \ + const event_group_object& nhl = create_event_group({{"en", "NHL"}, {"zh_Hans", "國家冰球聯盟"}, {"ja", "ナショナルホッケーリーグ"}}, ice_hockey.id); \ + const event_object& capitals_vs_blackhawks = create_event({{"en", "2016-17"}}, nhl.id, {capitals.id, blackhawks.id}); \ + const betting_market_group_object& moneyline_betting_markets = create_betting_market_group(capitals_vs_blackhawks.id, moneyline_market_options{}); \ + const betting_market_object& capitals_win_market = create_betting_market(moneyline_betting_markets.id, {{"en", "Washington Capitals win"}}, asset_id_type()); \ + const betting_market_object& blackhawks_win_market = create_betting_market(moneyline_betting_markets.id, {{"en", "Chicago Blackhawks win"}}, asset_id_type()); + + +#if 0 +BOOST_AUTO_TEST_CASE(generate_block) +{ + try + { + ACTORS( (alice)(bob) ); + + // failure if ACTORS + generate_blocks(10); + + } FC_LOG_AND_RETHROW() +} +#endif + +BOOST_AUTO_TEST_CASE(simple_bet_win) +{ + try + { + ACTORS( (alice)(bob) ); + CREATE_ICE_HOCKEY_BETTING_MARKET(); + + // give alice and bob 10k each + transfer(account_id_type(), alice_id, asset(10000)); + transfer(account_id_type(), bob_id, asset(10000)); + + // place bets at 10:1 + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 2); + place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 20); + + // reverse positions at 1:1 + place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22); + place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22); + + } FC_LOG_AND_RETHROW() +} + + +BOOST_AUTO_TEST_CASE( peerplays_sport_create_test ) +{ + try + { + ACTORS( (alice)(bob) ); + CREATE_ICE_HOCKEY_BETTING_MARKET(); + + // give alice and bob 10M each + transfer(account_id_type(), alice_id, asset(10000000)); + transfer(account_id_type(), bob_id, asset(10000000)); + + // have bob lay a bet for 1M (+20k fees) at 1:1 odds + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */); + // have alice back a matching bet at 1:1 odds (also costing 1.02M) + place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 1000000 / 50 /* chain defaults to 2% fees */); + + BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000); + BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000); + + // caps win + resolve_betting_market(capitals_win_market.id, betting_market_resolution_type::win); + + BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000000 - 1000000 - 20000 + 2000000); + BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000000 - 1000000 - 20000); + + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( chained_market_create_test ) +{ + // Often you will want to create several objects that reference each other at the same time. + // To facilitate this, many of the betting market operations allow you to use "relative" object ids, + // which let you can create, for example, an event in the 2nd operation in a transaction where the + // event group id is set to the id of an event group created in the 1st operation in a tranasction. + try + { + { + const flat_set& active_witnesses = db.get_global_properties().active_witnesses; + + BOOST_TEST_MESSAGE("Creating a sport and competitors in the same proposal"); + { + // operation 0 in the transaction + sport_create_operation sport_create_op; + sport_create_op.name.insert(internationalized_string_type::value_type("en", "Ice Hockey")); + sport_create_op.name.insert(internationalized_string_type::value_type("zh_Hans", "冰球")); + sport_create_op.name.insert(internationalized_string_type::value_type("ja", "アイスホッケー")); + + // operation 1 + competitor_create_operation competitor1_create_op; + competitor1_create_op.sport_id = object_id_type(relative_protocol_ids, 0, 0); + competitor1_create_op.name.insert(internationalized_string_type::value_type("en", "Washington Capitals")); + competitor1_create_op.name.insert(internationalized_string_type::value_type("zh_Hans", "華盛頓首都隊")); + competitor1_create_op.name.insert(internationalized_string_type::value_type("ja", "ワシントン・キャピタルズ")); + //BOOST_TEST_MESSAGE("Just constructed competitor_create_operation " << fc::json::to_pretty_string(competitor1_create_op)); + + // operation 2 + competitor_create_operation competitor2_create_op; + competitor2_create_op.sport_id = object_id_type(relative_protocol_ids, 0, 0); + competitor2_create_op.name.insert(internationalized_string_type::value_type("en", "Chicago Blackhawks")); + competitor2_create_op.name.insert(internationalized_string_type::value_type("zh_Hans", "芝加哥黑鷹")); + competitor2_create_op.name.insert(internationalized_string_type::value_type("ja", "シカゴ・ブラックホークス")); + + // operation 3 + event_group_create_operation event_group_create_op; + event_group_create_op.name.insert(internationalized_string_type::value_type("en", "NHL")); + event_group_create_op.name.insert(internationalized_string_type::value_type("zh_Hans", "國家冰球聯盟")); + event_group_create_op.name.insert(internationalized_string_type::value_type("ja", "ナショナルホッケーリーグ")); + event_group_create_op.sport_id = object_id_type(relative_protocol_ids, 0, 0); + + // operation 4 + // leave name and start time blank + event_create_operation event_create_op; + event_create_op.season.insert(internationalized_string_type::value_type("en", "2016-17")); + event_create_op.event_group_id = object_id_type(relative_protocol_ids, 0, 3); + event_create_op.competitors.push_back(object_id_type(relative_protocol_ids, 0, 1)); + event_create_op.competitors.push_back(object_id_type(relative_protocol_ids, 0, 2)); + + // operation 5 + betting_market_group_create_operation betting_market_group_create_op; + betting_market_group_create_op.event_id = object_id_type(relative_protocol_ids, 0, 4); + betting_market_group_create_op.options = moneyline_market_options{}; + + // operation 6 + betting_market_create_operation caps_win_betting_market_create_op; + caps_win_betting_market_create_op.group_id = object_id_type(relative_protocol_ids, 0, 5); + caps_win_betting_market_create_op.payout_condition.insert(internationalized_string_type::value_type("en", "Washington Capitals win")); + caps_win_betting_market_create_op.asset_id = asset_id_type(); + + // operation 7 + betting_market_create_operation blackhawks_win_betting_market_create_op; + blackhawks_win_betting_market_create_op.group_id = object_id_type(relative_protocol_ids, 0, 5); + blackhawks_win_betting_market_create_op.payout_condition.insert(internationalized_string_type::value_type("en", "Chicago Blackhawks win")); + blackhawks_win_betting_market_create_op.asset_id = asset_id_type(); + + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = (*active_witnesses.begin())(db).witness_account; + proposal_op.proposed_ops.emplace_back(sport_create_op); + proposal_op.proposed_ops.emplace_back(competitor1_create_op); + proposal_op.proposed_ops.emplace_back(competitor2_create_op); + proposal_op.proposed_ops.emplace_back(event_group_create_op); + proposal_op.proposed_ops.emplace_back(event_create_op); + proposal_op.proposed_ops.emplace_back(betting_market_group_create_op); + proposal_op.proposed_ops.emplace_back(caps_win_betting_market_create_op); + proposal_op.proposed_ops.emplace_back(blackhawks_win_betting_market_create_op); + proposal_op.expiration_time = db.head_block_time() + fc::days(1); + + signed_transaction tx; + tx.operations.push_back(proposal_op); + set_expiration(db, tx); + sign(tx, init_account_priv_key); + + db.push_transaction(tx); + } + + BOOST_REQUIRE_EQUAL(db.get_index_type().indices().size(), 1); + { + const proposal_object& prop = *db.get_index_type().indices().begin(); + + for (const witness_id_type& witness_id : active_witnesses) + { + BOOST_TEST_MESSAGE("Approving sport+competitors creation from witness " << fc::variant(witness_id).as()); + const witness_object& witness = witness_id(db); + const account_object& witness_account = witness.witness_account(db); + + proposal_update_operation pup; + pup.proposal = prop.id; + pup.fee_paying_account = witness_account.id; + //pup.key_approvals_to_add.insert(witness.signing_key); + pup.active_approvals_to_add.insert(witness_account.id); + + signed_transaction tx; + tx.operations.push_back( pup ); + set_expiration( db, tx ); + sign(tx, init_account_priv_key); + + db.push_transaction(tx, ~0); + if (db.get_index_type().indices().size() == 1) + { + BOOST_REQUIRE_EQUAL(db.get_index_type().indices().size(), 2); + //BOOST_TEST_MESSAGE("The sport creation operation has been approved, new sport object on the blockchain is " << fc::json::to_pretty_string(*db.get_index_type().indices().rbegin())); + //BOOST_TEST_MESSAGE("The first competitor object on the blockchain is " << fc::json::to_pretty_string(*db.get_index_type().indices().begin())); + break; + } + } + } + + } + + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_SUITE_END() + +// set up a fixture that places a series of two matched bets, we'll use this fixture to verify +// the result in all three possible outcomes +struct simple_bet_test_fixture : database_fixture { + betting_market_id_type capitals_win_betting_market_id; + simple_bet_test_fixture() + { + ACTORS( (alice)(bob) ); + CREATE_ICE_HOCKEY_BETTING_MARKET(); + + // give alice and bob 10k each + transfer(account_id_type(), alice_id, asset(10000)); + transfer(account_id_type(), bob_id, asset(10000)); + + // place bets at 10:1 + place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(100, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 2); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 11 * GRAPHENE_BETTING_ODDS_PRECISION, 20); + + // reverse positions at 1:1 + place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22); + place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1100, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 22); + + capitals_win_betting_market_id = capitals_win_market.id; + } +}; + +BOOST_FIXTURE_TEST_SUITE( simple_bet_tests, simple_bet_test_fixture ) + +BOOST_AUTO_TEST_CASE( win ) +{ + try + { + resolve_betting_market(capitals_win_betting_market_id, betting_market_resolution_type::win); + + GET_ACTOR(alice); + GET_ACTOR(bob); + + // alice starts with 10000, pays 100 (bet) + 2 (fee), wins 1100, then pays 1100 (bet) + 22 (fee), wins 0 + BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 - 2 + 1100 - 1100 - 22 + 0); + // bob starts with 10000, pays 1000 (bet) + 20 (fee), wins 0, then pays 1100 (bet) + 22 (fee), wins 2200 + BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 - 20 + 0 - 1100 - 22 + 2200); + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( not_win ) +{ + try + { + resolve_betting_market(capitals_win_betting_market_id, betting_market_resolution_type::not_win); + + GET_ACTOR(alice); + GET_ACTOR(bob); + + // alice starts with 10000, pays 100 (bet) + 2 (fee), wins 0, then pays 1100 (bet) + 22 (fee), wins 2200 + BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000 - 100 - 2 + 0 - 1100 - 22 + 2200); + // bob starts with 10000, pays 1000 (bet) + 20 (fee), wins 1100, then pays 1100 (bet) + 22 (fee), wins 0 + BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000 - 1000 - 20 + 1100 - 1100 - 22 + 0); + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( cancel ) +{ + try + { + resolve_betting_market(capitals_win_betting_market_id, betting_market_resolution_type::cancel); + + GET_ACTOR(alice); + GET_ACTOR(bob); + + // alice and bob both start with 10000, they should end with 10000 + BOOST_CHECK_EQUAL(get_balance(alice_id, asset_id_type()), 10000); + BOOST_CHECK_EQUAL(get_balance(bob_id, asset_id_type()), 10000); + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_SUITE_END() + +struct simple_bet_test_fixture_2 : database_fixture { + betting_market_id_type capitals_win_betting_market_id; + simple_bet_test_fixture_2() + { + ACTORS( (alice)(bob) ); + CREATE_ICE_HOCKEY_BETTING_MARKET(); + + // give alice and bob 10k each + transfer(account_id_type(), alice_id, asset(10000)); + transfer(account_id_type(), bob_id, asset(10000)); + + // alice backs 1000 at 1:1, matches + place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 20); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 20); + + // now alice lays at 2500 at 1:1. This should require a deposit of 500, with the remaining 200 being funded from exposure + place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(2500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 50); + + // match the bet bit by bit. bob matches 500 of alice's 2500 bet. This effectively cancels half of bob's lay position + // so he immediately gets 500 back. It reduces alice's back position, but doesn't return any money to her (all 2000 of her exposure + // was already "promised" to her lay bet, so the 500 she would have received is placed in her refundable_unmatched_bets) + place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 10); + + // match another 500, which will fully cancel bob's lay position and return the other 500 he had locked up in his position. + // alice's back position is now canceled, 1500 remains of her unmatched lay bet, and the 500 from canceling her position has + // been moved to her refundable_unmatched_bets + place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(500, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION, 10); + + capitals_win_betting_market_id = capitals_win_market.id; + } +}; + +//#define BOOST_TEST_MODULE "C++ Unit Tests for Graphene Blockchain Database" +#include +#include +#include + +boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { + std::srand(time(NULL)); + std::cout << "Random number generator seeded to " << time(NULL) << std::endl; + return nullptr; +} +