diff --git a/.gitignore b/.gitignore index fe5c9c4b..c72b010a 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,4 @@ object_database/* *.pyo .vscode .DS_Store -.idea \ No newline at end of file +.idea diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index a6db2008..4d4f4dec 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -681,6 +681,20 @@ namespace graphene { namespace app { crypto_api::crypto_api(){}; + blind_signature crypto_api::blind_sign( const extended_private_key_type& key, const blinded_hash& hash, int i ) + { + return fc::ecc::extended_private_key( key ).blind_sign( hash, i ); + } + + signature_type crypto_api::unblind_signature( const extended_private_key_type& key, + const extended_public_key_type& bob, + const blind_signature& sig, + const fc::sha256& hash, + int i ) + { + return fc::ecc::extended_private_key( key ).unblind_signature( extended_public_key( bob ), sig, hash, i ); + } + commitment_type crypto_api::blind( const blind_factor_type& blind, uint64_t value ) { return fc::ecc::blind( blind, value ); diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 26ae23b0..dc18db5c 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -162,11 +162,10 @@ namespace detail { { // t.me/peerplays #seednodes vector seeds = { - // BEATRICE SEEDS: - // "ppy-beatrice-seed.blckchnd.com:6666", - // "159.69.223.206:7777", - // "51.38.237.243:9666", - // "pbsa-beatrice.blockchainprojectsbv.com:9195" + "ppy-beatrice-seed.blckchnd.com:6666", + "159.69.223.206:7777", + "51.38.237.243:9666", + "pbsa-beatrice.blockchainprojectsbv.com:9195" // OTTHER SEEDS: // "seed.ppy.blckchnd.com:6112", // blckchnd // "ppy.esteem.ws:7777", // good-karma diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 187d8374..8dd52e08 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -113,7 +113,6 @@ class database_api_impl : public std::enable_shared_from_this vector get_unmatched_bets_for_bettor(betting_market_id_type, account_id_type) const; vector get_all_unmatched_bets_for_bettor(account_id_type) const; - // Lottery Assets vector get_lotteries( asset_id_type stop = asset_id_type(), unsigned limit = 100, diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 49c7f77e..6f90938d 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -737,7 +737,7 @@ FC_API(graphene::app::database_api, (list_betting_markets) (get_unmatched_bets_for_bettor) (get_all_unmatched_bets_for_bettor) - + // Sweeps (get_lotteries) (get_account_lotteries) diff --git a/libraries/chain/betting_market_group_object.cpp b/libraries/chain/betting_market_group_object.cpp index 71135e07..584039c9 100644 --- a/libraries/chain/betting_market_group_object.cpp +++ b/libraries/chain/betting_market_group_object.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/libraries/chain/betting_market_object.cpp b/libraries/chain/betting_market_object.cpp index cb0e006e..a0beeb7d 100644 --- a/libraries/chain/betting_market_object.cpp +++ b/libraries/chain/betting_market_object.cpp @@ -25,7 +25,7 @@ #define DEFAULT_LOGGER "betting" #include #include -#include +#include #include #include @@ -101,7 +101,7 @@ share_type bet_object::get_exact_matching_amount() const /* static */ std::pair bet_object::get_ratio(bet_multiplier_type backer_multiplier) { - share_type gcd = boost::integer::gcd(GRAPHENE_BETTING_ODDS_PRECISION, static_cast(backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION)); + share_type gcd = boost::math::gcd(GRAPHENE_BETTING_ODDS_PRECISION, backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION); return std::make_pair(GRAPHENE_BETTING_ODDS_PRECISION / gcd, (backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION) / gcd); } @@ -112,13 +112,13 @@ std::pair bet_object::get_ratio() const share_type bet_object::get_minimum_matchable_amount() const { - share_type gcd = boost::integer::gcd(GRAPHENE_BETTING_ODDS_PRECISION, static_cast(backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION)); + share_type gcd = boost::math::gcd(GRAPHENE_BETTING_ODDS_PRECISION, backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION); return (back_or_lay == bet_type::back ? GRAPHENE_BETTING_ODDS_PRECISION : backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION) / gcd; } share_type bet_object::get_minimum_matching_amount() const { - share_type gcd = boost::integer::gcd(GRAPHENE_BETTING_ODDS_PRECISION, static_cast(backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION)); + share_type gcd = boost::math::gcd(GRAPHENE_BETTING_ODDS_PRECISION, backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION); return (back_or_lay == bet_type::lay ? GRAPHENE_BETTING_ODDS_PRECISION : backer_multiplier - GRAPHENE_BETTING_ODDS_PRECISION) / gcd; } diff --git a/libraries/chain/include/graphene/chain/asset_evaluator.hpp b/libraries/chain/include/graphene/chain/asset_evaluator.hpp index 4dd4a930..27fb1aa2 100644 --- a/libraries/chain/include/graphene/chain/asset_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/asset_evaluator.hpp @@ -35,8 +35,7 @@ namespace graphene { namespace chain { void_result do_evaluate( const asset_create_operation& o ); object_id_type do_apply( const asset_create_operation& o ); - - // copied from bitshares. (https://github.com/bitshares/bitshares-core/issues/429) + /** override the default behavior defined by generic_evalautor which is to * post the fee to fee_paying_account_stats.pending_fees */ diff --git a/libraries/chain/include/graphene/chain/event_group_object.hpp b/libraries/chain/include/graphene/chain/event_group_object.hpp index 75d26ff8..38fb9f2d 100644 --- a/libraries/chain/include/graphene/chain/event_group_object.hpp +++ b/libraries/chain/include/graphene/chain/event_group_object.hpp @@ -27,6 +27,7 @@ #include #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/event_object.hpp b/libraries/chain/include/graphene/chain/event_object.hpp index c97e7660..e6989240 100644 --- a/libraries/chain/include/graphene/chain/event_object.hpp +++ b/libraries/chain/include/graphene/chain/event_object.hpp @@ -28,6 +28,7 @@ #include #include +#include namespace graphene { namespace chain { class event_object; diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index b98add00..9082d170 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -30,7 +30,7 @@ namespace graphene { namespace chain { struct fee_schedule; } } namespace graphene { namespace chain { - struct parameter_extension + struct bet_parameter_extension { optional< bet_multiplier_type > min_bet_multiplier; optional< bet_multiplier_type > max_bet_multiplier; @@ -44,7 +44,9 @@ namespace graphene { namespace chain { asset_id_type sweeps_distribution_asset = SWEEPS_DEFAULT_DISTRIBUTION_ASSET; account_id_type sweeps_vesting_accumulator_account = SWEEPS_ACCUMULATOR_ACCOUNT; }; - typedef static_variant parameter_extension; + + typedef static_variant parameter_extension; + struct chain_parameters { /** using a smart ref breaks the circular dependency created between operations and the fee schedule */ @@ -120,7 +122,7 @@ namespace graphene { namespace chain { } } // graphene::chain -FC_REFLECT( graphene::chain::parameter_extension, +FC_REFLECT( graphene::chain::bet_parameter_extension, (min_bet_multiplier) (max_bet_multiplier) (betting_rake_fee_percentage) diff --git a/libraries/deterministic_openssl_rand/CMakeLists.txt b/libraries/deterministic_openssl_rand/CMakeLists.txt new file mode 100644 index 00000000..1d9c5870 --- /dev/null +++ b/libraries/deterministic_openssl_rand/CMakeLists.txt @@ -0,0 +1,28 @@ + +file(GLOB headers "include/graphene/utilities/*.hpp") + +set(sources deterministic_openssl_rand.cpp + ${headers}) + +add_library( deterministic_openssl_rand + ${sources} + ${HEADERS} ) +target_link_libraries( deterministic_openssl_rand fc ) +target_include_directories( deterministic_openssl_rand + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/../blockchain/include" + ) + +if (USE_PCH) + set_target_properties(deterministic_openssl_rand PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) + cotire(deterministic_openssl_rand) +endif(USE_PCH) + +install( TARGETS + deterministic_openssl_rand + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +install( FILES ${headers} DESTINATION "include/graphene/deterministic_openssl_rand" ) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 3c8ebbf8..5618d26a 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2063,6 +2063,5 @@ FC_API( graphene::wallet::wallet_api, (get_binned_order_book) (get_matched_bets_for_bettor) (get_all_matched_bets_for_bettor) - (buy_ticket) ) diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 2085cbb5..e73f69e5 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -128,6 +128,17 @@ int main(int argc, char** argv) { std::cout << app_options << "\n"; return 0; } + if (options.count("version")) + { + std::string witness_version(graphene::utilities::git_revision_description); + const size_t pos = witness_version.find('/'); + if( pos != std::string::npos && witness_version.size() > pos ) + witness_version = witness_version.substr( pos + 1 ); + std::cerr << "Version: " << witness_version << "\n"; + std::cerr << "Git Revision: " << graphene::utilities::git_revision_sha << "\n"; + std::cerr << "Built: " << __DATE__ " at " __TIME__ << "\n"; + return 0; + } fc::path data_dir; if( options.count("data-dir") ) @@ -193,3 +204,109 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } } + +// logging config is too complicated to be parsed by boost::program_options, +// so we do it by hand +// +// Currently, you can only specify the filenames and logging levels, which +// are all most users would want to change. At a later time, options can +// be added to control rotation intervals, compression, and other seldom- +// used features +void write_default_logging_config_to_stream(std::ostream& out) +{ + out << "# declare an appender named \"stderr\" that writes messages to the console\n" + "[log.console_appender.stderr]\n" + "stream=std_error\n\n" + "# declare an appender named \"p2p\" that writes messages to p2p.log\n" + "[log.file_appender.p2p]\n" + "filename=logs/p2p/p2p.log\n" + "# filename can be absolute or relative to this config file\n\n" + "# route any messages logged to the default logger to the \"stderr\" logger we\n" + "# declared above, if they are info level are higher\n" + "[logger.default]\n" + "level=info\n" + "appenders=stderr\n\n" + "# route messages sent to the \"p2p\" logger to the p2p appender declared above\n" + "[logger.p2p]\n" + "level=info\n" + "appenders=p2p\n\n"; +} + +fc::optional load_logging_config_from_ini_file(const fc::path& config_ini_filename) +{ + try + { + fc::logging_config logging_config; + bool found_logging_config = false; + + boost::property_tree::ptree config_ini_tree; + boost::property_tree::ini_parser::read_ini(config_ini_filename.preferred_string().c_str(), config_ini_tree); + for (const auto& section : config_ini_tree) + { + const std::string& section_name = section.first; + const boost::property_tree::ptree& section_tree = section.second; + + const std::string console_appender_section_prefix = "log.console_appender."; + const std::string file_appender_section_prefix = "log.file_appender."; + const std::string logger_section_prefix = "logger."; + + if (boost::starts_with(section_name, console_appender_section_prefix)) + { + std::string console_appender_name = section_name.substr(console_appender_section_prefix.length()); + std::string stream_name = section_tree.get("stream"); + + // construct a default console appender config here + // stdout/stderr will be taken from ini file, everything else hard-coded here + fc::console_appender::config console_appender_config; + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::debug, + fc::console_appender::color::green)); + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::warn, + fc::console_appender::color::brown)); + console_appender_config.level_colors.emplace_back( + fc::console_appender::level_color(fc::log_level::error, + fc::console_appender::color::cyan)); + console_appender_config.stream = fc::variant(stream_name).as(); + logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config))); + found_logging_config = true; + } + else if (boost::starts_with(section_name, file_appender_section_prefix)) + { + std::string file_appender_name = section_name.substr(file_appender_section_prefix.length()); + fc::path file_name = section_tree.get("filename"); + if (file_name.is_relative()) + file_name = fc::absolute(config_ini_filename).parent_path() / file_name; + + + // construct a default file appender config here + // filename will be taken from ini file, everything else hard-coded here + fc::file_appender::config file_appender_config; + file_appender_config.filename = file_name; + file_appender_config.flush = true; + file_appender_config.rotate = true; + file_appender_config.rotation_interval = fc::hours(1); + file_appender_config.rotation_limit = fc::days(1); + logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config))); + found_logging_config = true; + } + else if (boost::starts_with(section_name, logger_section_prefix)) + { + std::string logger_name = section_name.substr(logger_section_prefix.length()); + std::string level_string = section_tree.get("level"); + std::string appenders_string = section_tree.get("appenders"); + fc::logger_config logger_config(logger_name); + logger_config.level = fc::variant(level_string).as(); + boost::split(logger_config.appenders, appenders_string, + boost::is_any_of(" ,"), + boost::token_compress_on); + logging_config.loggers.push_back(logger_config); + found_logging_config = true; + } + } + if (found_logging_config) + return logging_config; + else + return fc::optional(); + } +} diff --git a/tests/betting/betting_tests.cpp b/tests/betting/betting_tests.cpp index 3988c71f..a7c259a8 100644 --- a/tests/betting/betting_tests.cpp +++ b/tests/betting/betting_tests.cpp @@ -377,41 +377,49 @@ BOOST_AUTO_TEST_CASE(binned_order_books) // place lay bets at decimal odds of 1.55, 1.6, 1.65, 1.66, and 1.67 // these bets will get rounded down, actual amounts are 99, 99, 91, 99, and 67 -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); -// -// binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); -// idump((binned_orders_point_one)); -// -// // the binned orders returned should be chosen so that we if we assume those orders are real and we place -// // matching lay orders, we will completely consume the underlying orders and leave no orders on the books -// // -// // for the bets bob placed above, we shoudl get 356 @ 1.6, 99 @ 1.5 -// BOOST_CHECK_EQUAL(binned_orders_point_one.aggregated_back_bets.size(), 0u); -// BOOST_CHECK_EQUAL(binned_orders_point_one.aggregated_lay_bets.size(), 2u); -// for (const graphene::bookie::order_bin& binned_order : binned_orders_point_one.aggregated_lay_bets) -// { -// // compute the matching lay order -// share_type back_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::lay, true /* round up */); -// ilog("Alice is backing with ${back_amount} at odds ${odds} to match the binned lay amount ${lay_amount}", ("back_amount", back_amount)("odds", binned_order.backer_multiplier)("lay_amount", binned_order.amount_to_bet)); -// place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier); -// -// } -// -// -// bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); -// while (bet_iter != bet_odds_idx.end() && -// bet_iter->betting_market_id == capitals_win_market.id) -// { -// idump((*bet_iter)); -// ++bet_iter; -// } -// -// BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)) == bet_odds_idx.end()); -// + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 155 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 16 * GRAPHENE_BETTING_ODDS_PRECISION / 10); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 165 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 166 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 167 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + + binned_orders_point_one = bookie_api.get_binned_order_book(capitals_win_market.id, 1); + idump((binned_orders_point_one)); + + // the binned orders returned should be chosen so that we if we assume those orders are real and we place + // matching lay orders, we will completely consume the underlying orders and leave no orders on the books + // + // for the bets bob placed above, we shoudl get 356 @ 1.6, 99 @ 1.5 + BOOST_CHECK_EQUAL(binned_orders_point_one.aggregated_back_bets.size(), 0u); + BOOST_CHECK_EQUAL(binned_orders_point_one.aggregated_lay_bets.size(), 2u); + for (const graphene::bookie::order_bin& binned_order : binned_orders_point_one.aggregated_lay_bets) + { + // compute the matching lay order + share_type back_amount = bet_object::get_approximate_matching_amount(binned_order.amount_to_bet, binned_order.backer_multiplier, bet_type::lay, true /* round up */); + ilog("Alice is backing with ${back_amount} at odds ${odds} to match the binned lay amount ${lay_amount}", ("back_amount", back_amount)("odds", binned_order.backer_multiplier)("lay_amount", binned_order.amount_to_bet)); + place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(back_amount, asset_id_type()), binned_order.backer_multiplier); + + ilog("After alice's bet, order book is:"); + bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + while (bet_iter != bet_odds_idx.end() && + bet_iter->betting_market_id == capitals_win_market.id) + { + idump((*bet_iter)); + ++bet_iter; + } + } + + + bet_iter = bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)); + while (bet_iter != bet_odds_idx.end() && + bet_iter->betting_market_id == capitals_win_market.id) + { + idump((*bet_iter)); + ++bet_iter; + } + + BOOST_CHECK(bet_odds_idx.lower_bound(std::make_tuple(capitals_win_market.id)) == bet_odds_idx.end()); + } FC_LOG_AND_RETHROW() } @@ -898,43 +906,42 @@ BOOST_AUTO_TEST_CASE(bet_reversal_test) FC_LOG_AND_RETHROW() } -//This test case need some analysis and commneting out for the time being -// BOOST_AUTO_TEST_CASE(bet_against_exposure_test) -// { -// // test whether we can bet our entire balance in one direction, have it match, then reverse our bet (while having zero balance) -// try -// { -// generate_blocks(1); -// ACTORS( (alice)(bob) ); -// CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); -// -// transfer(account_id_type(), alice_id, asset(10000000)); -// transfer(account_id_type(), bob_id, asset(10000000)); -// int64_t alice_expected_balance = 10000000; -// BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); -// int64_t bob_expected_balance = 10000000; -// BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); -// -// // back with alice's entire balance -// place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); -// alice_expected_balance -= 10000000; -// BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); -// -// // lay with bob's entire balance, which fully matches bob's bet -// place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); -// bob_expected_balance -= 10000000; -// BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); -// -// // reverse the bet -// place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); -// BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); -// -// // try to re-reverse it, but go too far -// BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); -// BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); -// } -// FC_LOG_AND_RETHROW() -// } +BOOST_AUTO_TEST_CASE(bet_against_exposure_test) +{ + // test whether we can bet our entire balance in one direction, have it match, then reverse our bet (while having zero balance) + try + { + generate_blocks(1); + ACTORS( (alice)(bob) ); + CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); + + transfer(account_id_type(), alice_id, asset(10000000)); + transfer(account_id_type(), bob_id, asset(10000000)); + int64_t alice_expected_balance = 10000000; + BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); + int64_t bob_expected_balance = 10000000; + BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); + + // back with alice's entire balance + place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + alice_expected_balance -= 10000000; + BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); + + // lay with bob's entire balance, which fully matches bob's bet + place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(10000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + bob_expected_balance -= 10000000; + BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance); + + // reverse the bet + place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(20000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); + BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); + + // try to re-reverse it, but go too far + BOOST_CHECK_THROW( place_bet(alice_id, capitals_win_market.id, bet_type::back, asset(30000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION), fc::exception); + BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance); + } + FC_LOG_AND_RETHROW() +} BOOST_AUTO_TEST_CASE(persistent_objects_test) { @@ -1527,18 +1534,17 @@ BOOST_AUTO_TEST_CASE(sport_delete_test_not_proposal) } FC_LOG_AND_RETHROW() } -// No need for the below test as it shows in failed test case list. Should enable when sports related changes applied -// BOOST_AUTO_TEST_CASE(sport_delete_test_not_existed_sport) -// { -// try -// { -// CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); -// -// delete_sport(ice_hockey.id); -// -// BOOST_CHECK_THROW(delete_sport(ice_hockey.id), fc::exception); -// } FC_LOG_AND_RETHROW() -// } +BOOST_AUTO_TEST_CASE(sport_delete_test_not_existed_sport) +{ + try + { + CREATE_ICE_HOCKEY_BETTING_MARKET(false, 0); + + delete_sport(ice_hockey.id); + + BOOST_CHECK_THROW(delete_sport(ice_hockey.id), fc::exception); + } FC_LOG_AND_RETHROW() +} BOOST_AUTO_TEST_CASE(event_group_update_test) { @@ -2776,26 +2782,24 @@ BOOST_FIXTURE_TEST_CASE( another_event_group_update_test, database_fixture) update_event_group(nhl.id, fc::optional(), name); update_event_group(nhl.id, sport_id, fc::optional()); update_event_group(nhl.id, sport_id, name); - - //Disabling the below 4 TRY_EXPECT_THROW lines to not throw anything beacuse functioning as expected - + // trx_state->_is_proposed_trx //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional(), true), fc::exception); - // TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional(), true), fc::exception, "_is_proposed_trx"); + TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional(), true), fc::exception, "_is_proposed_trx"); // #! nothing to change //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional()), fc::exception, "nothing to change"); + TRY_EXPECT_THROW(try_update_event_group(nhl.id, fc::optional(), fc::optional()), fc::exception, "nothing to change"); // #! sport_id must refer to a sport_id_type sport_id = capitals_win_market.id; //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "sport_id must refer to a sport_id_type"); + TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "sport_id must refer to a sport_id_type"); // #! invalid sport specified sport_id = sport_id_type(13); //GRAPHENE_REQUIRE_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception); - //TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "invalid sport specified"); + TRY_EXPECT_THROW(try_update_event_group(nhl.id, sport_id, fc::optional()), fc::exception, "invalid sport specified"); place_bet(bob_id, capitals_win_market.id, bet_type::lay, asset(1000000, asset_id_type()), 2 * GRAPHENE_BETTING_ODDS_PRECISION); @@ -2938,65 +2942,60 @@ BOOST_AUTO_TEST_CASE( wimbledon_2017_gentelmen_singles_final_test ) // reworked check_transasction for duplicate // now should not through an exception when there are different events with the same betting_market_group // and or the same betting_market -// Need to revisit the following test, commeting for time being****** -// BOOST_AUTO_TEST_CASE( check_transaction_for_duplicate_reworked_test ) -// { -// try -// { -// std::vector names_vec(104); -// -// // create 104 pattern for first name -// for( char co = 'A'; co <= 'D'; ++co ) { -// for( char ci = 'A'; ci <= 'Z'; ++ci ) { -// std::string first_name = std::to_string(co) + std::to_string(ci); -// std::string second_name = first_name + first_name; -// names_vec.push_back( {{ first_name, second_name }} ); -// } -// } -// -// sport_id_type sport_id = create_sport( {{"SN","SPORT_NAME"}} ).id; -// -// event_group_id_type event_group_id = create_event_group( {{"EG", "EVENT_GROUP"}}, sport_id ).id; -// -// betting_market_rules_id_type betting_market_rules_id = -// create_betting_market_rules( {{"EN", "Rules"}}, {{"EN", "Some rules"}} ).id; -// -// for( const auto& name : names_vec ) -// { -// proposal_create_operation pcop = proposal_create_operation::committee_proposal( -// db.get_global_properties().parameters, -// db.head_block_time() -// ); -// pcop.review_period_seconds.reset(); -// pcop.review_period_seconds = db.get_global_properties().parameters.committee_proposal_review_period * 2; -// -// event_create_operation evcop; -// evcop.event_group_id = event_group_id; -// evcop.name = name; -// evcop.season = name; -// -// betting_market_group_create_operation bmgcop; -// bmgcop.description = name; -// bmgcop.event_id = object_id_type(relative_protocol_ids, 0, 0); -// bmgcop.rules_id = betting_market_rules_id; -// bmgcop.asset_id = asset_id_type(); -// -// betting_market_create_operation bmcop; -// bmcop.group_id = object_id_type(relative_protocol_ids, 0, 1); -// bmcop.payout_condition.insert( internationalized_string_type::value_type( "CN", "CONDI_NAME" ) ); -// -// pcop.proposed_ops.emplace_back( evcop ); -// pcop.proposed_ops.emplace_back( bmgcop ); -// pcop.proposed_ops.emplace_back( bmcop ); -// -// signed_transaction trx; -// set_expiration( db, trx ); -// trx.operations.push_back( pcop ); -// -// process_operation_by_witnesses( pcop ); -// } -// }FC_LOG_AND_RETHROW() -// } +BOOST_AUTO_TEST_CASE( check_transaction_for_duplicate_reworked_test ) +{ + std::vector names_vec(104); + + // create 104 pattern for first name + for( char co = 'A'; co <= 'D'; ++co ) { + for( char ci = 'A'; ci <= 'Z'; ++ci ) { + std::string first_name = std::to_string(co) + std::to_string(ci); + std::string second_name = first_name + first_name; + names_vec.push_back( {{ first_name, second_name }} ); + } + } + + sport_id_type sport_id = create_sport( {{"SN","SPORT_NAME"}} ).id; + + event_group_id_type event_group_id = create_event_group( {{"EG", "EVENT_GROUP"}}, sport_id ).id; + + betting_market_rules_id_type betting_market_rules_id = + create_betting_market_rules( {{"EN", "Rules"}}, {{"EN", "Some rules"}} ).id; + + for( const auto& name : names_vec ) + { + proposal_create_operation pcop = proposal_create_operation::committee_proposal( + db.get_global_properties().parameters, + db.head_block_time() + ); + pcop.review_period_seconds.reset(); + + event_create_operation evcop; + evcop.event_group_id = event_group_id; + evcop.name = name; + evcop.season = name; + + betting_market_group_create_operation bmgcop; + bmgcop.description = name; + bmgcop.event_id = object_id_type(relative_protocol_ids, 0, 0); + bmgcop.rules_id = betting_market_rules_id; + bmgcop.asset_id = asset_id_type(); + + betting_market_create_operation bmcop; + bmcop.group_id = object_id_type(relative_protocol_ids, 0, 1); + bmcop.payout_condition.insert( internationalized_string_type::value_type( "CN", "CONDI_NAME" ) ); + + pcop.proposed_ops.emplace_back( evcop ); + pcop.proposed_ops.emplace_back( bmgcop ); + pcop.proposed_ops.emplace_back( bmcop ); + + signed_transaction trx; + set_expiration( db, trx ); + trx.operations.push_back( pcop ); + + process_operation_by_witnesses( pcop ); + } +} BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 5d360ebd..468959af 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -89,9 +89,11 @@ database_fixture::database_fixture() boost::program_options::variables_map options; - // genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); - genesis_state.initial_timestamp = time_point_sec( (fc::time_point::now().sec_since_epoch() / GRAPHENE_DEFAULT_BLOCK_INTERVAL) * GRAPHENE_DEFAULT_BLOCK_INTERVAL ); -// genesis_state.initial_parameters.witness_schedule_algorithm = GRAPHENE_WITNESS_SHUFFLED_ALGORITHM; + genesis_state.initial_timestamp = time_point_sec( GRAPHENE_TESTING_GENESIS_TIMESTAMP ); + //int back_to_the_past = 0; + //back_to_the_past = 7 * 24 * 60 * 60; // week + //genesis_state.initial_timestamp = time_point_sec( (fc::time_point::now().sec_since_epoch() - back_to_the_past) / GRAPHENE_DEFAULT_BLOCK_INTERVAL * GRAPHENE_DEFAULT_BLOCK_INTERVAL ); + genesis_state.initial_parameters.witness_schedule_algorithm = GRAPHENE_WITNESS_SHUFFLED_ALGORITHM; genesis_state.initial_active_witnesses = 10; for( unsigned i = 0; i < genesis_state.initial_active_witnesses; ++i ) @@ -713,8 +715,7 @@ const witness_object& database_fixture::create_witness( const account_object& ow secret_hash_type::encoder enc; fc::raw::pack(enc, signing_private_key); fc::raw::pack(enc, secret_hash_type()); - op.initial_secret = enc.result(); - + op.initial_secret = secret_hash_type::hash(enc.result()); trx.operations.push_back(op); trx.validate(); processed_transaction ptx = db.push_transaction(trx, ~0); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index a81710b5..87327c21 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -842,7 +842,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture ) sign( trx, get_account("init7" ).active.get_keys().front(),init_account_priv_key); */ db.push_transaction(trx); -// BOOST_CHECK(proposal_id_type()(db).is_authorized_to_execute(db)); + BOOST_CHECK(proposal_id_type()(db).is_authorized_to_execute(db)); } BOOST_TEST_MESSAGE( "Verifying that the interval didn't change immediately" ); @@ -863,12 +863,12 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture ) generate_block(); // get the maintenance skip slots out of the way BOOST_TEST_MESSAGE( "Verify that the new block interval is 1 second" ); -// BOOST_CHECK_EQUAL(db.get_global_properties().parameters.block_interval, 1); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.block_interval, 1); past_time = db.head_block_time().sec_since_epoch(); generate_block(); -// BOOST_CHECK_EQUAL(db.head_block_time().sec_since_epoch() - past_time, 1); + BOOST_CHECK_EQUAL(db.head_block_time().sec_since_epoch() - past_time, 1); generate_block(); -// BOOST_CHECK_EQUAL(db.head_block_time().sec_since_epoch() - past_time, 2); + BOOST_CHECK_EQUAL(db.head_block_time().sec_since_epoch() - past_time, 2); } FC_LOG_AND_RETHROW() } BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture ) @@ -1087,7 +1087,6 @@ BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, database_fixture ) // the test written in 2015 should be revised, currently it is not possible to push block to db2 // without skip_witness_signature | skip_witness_schedule_check | skip_authority_check -/* BOOST_FIXTURE_TEST_CASE( transaction_invalidated_in_cache, database_fixture ) { try @@ -1112,9 +1111,7 @@ BOOST_FIXTURE_TEST_CASE( transaction_invalidated_in_cache, database_fixture ) while( db2.head_block_num() < db.head_block_num() ) { optional< signed_block > b = db.fetch_block_by_number( db2.head_block_num()+1 ); - db2.push_block(*b, database::skip_witness_signature| - database::skip_authority_check| - database::skip_witness_schedule_check); + db2.push_block(*b, database::skip_witness_signature); } BOOST_CHECK( db2.get( alice_id ).name == "alice" ); BOOST_CHECK( db2.get( bob_id ).name == "bob" ); @@ -1238,7 +1235,6 @@ BOOST_FIXTURE_TEST_CASE( transaction_invalidated_in_cache, database_fixture ) throw; } } -*/ BOOST_AUTO_TEST_CASE( genesis_reserve_ids ) { diff --git a/tests/tests/fee_tests.cpp b/tests/tests/fee_tests.cpp index 324f20fc..0cfcdc5d 100644 --- a/tests/tests/fee_tests.cpp +++ b/tests/tests/fee_tests.cpp @@ -79,16 +79,17 @@ BOOST_AUTO_TEST_CASE( nonzero_fee_test ) } } -// fails -// BOOST_AUTO_TEST_CASE(asset_claim_fees_test) -// { -// try -// { -// ACTORS((alice)(bob)(izzy)(jill)); -// // Izzy issues asset to Alice -// // Jill issues asset to Bob -// // Alice and Bob trade in the market and pay fees -// // Verify that Izzy and Jill can claim the fees +// assertion if "No asset in the trade is CORE." in market_evaluator.cpp +#if 0 +BOOST_AUTO_TEST_CASE(asset_claim_fees_test) +{ + try + { + ACTORS((alice)(bob)(izzy)(jill)); + // Izzy issues asset to Alice + // Jill issues asset to Bob + // Alice and Bob trade in the market and pay fees + // Verify that Izzy and Jill can claim the fees // const share_type core_prec = asset::scaled_precision( asset_id_type()(db).precision ); @@ -203,16 +204,17 @@ BOOST_AUTO_TEST_CASE( nonzero_fee_test ) // GRAPHENE_REQUIRE_THROW( claim_fees( izzy_id, izzy_satoshi ), fc::exception ); // BOOST_CHECK( izzycoin.dynamic_asset_data_id(db).accumulated_fees == _izzy(0).amount ); -// // can claim in multiple goes -// claim_fees( jill_id, _jill(4) ); -// BOOST_CHECK( jillcoin.dynamic_asset_data_id(db).accumulated_fees == _jill(2).amount ); -// GRAPHENE_REQUIRE_THROW( claim_fees( jill_id, _jill(2) + jill_satoshi ), fc::exception ); -// claim_fees( jill_id, _jill(2) ); -// BOOST_CHECK( jillcoin.dynamic_asset_data_id(db).accumulated_fees == _jill(0).amount ); -// } -// } -// FC_LOG_AND_RETHROW() -// } + // can claim in multiple goes + claim_fees( jill_id, _jill(4) ); + BOOST_CHECK( jillcoin.dynamic_asset_data_id(db).accumulated_fees == _jill(2).amount ); + GRAPHENE_REQUIRE_THROW( claim_fees( jill_id, _jill(2) + jill_satoshi ), fc::exception ); + claim_fees( jill_id, _jill(2) ); + BOOST_CHECK( jillcoin.dynamic_asset_data_id(db).accumulated_fees == _jill(0).amount ); + } + } + FC_LOG_AND_RETHROW() +} +#endif /////////////////////////////////////////////////////////////// // cashback_test infrastructure // @@ -266,313 +268,314 @@ struct actor_audit int64_t ref_pct = 0; // referrer percentage should be this }; -// BOOST_AUTO_TEST_CASE( cashback_test ) -// { try { -// /* Account Structure used in this test * -// * * -// * /-----------------\ /-------------------\ * -// * | life (Lifetime) | | rog (Lifetime) | * -// * \-----------------/ \-------------------/ * -// * | Ref&Reg | Refers | Registers | Registers * -// * | | 75 | 25 | * -// * v v v | * -// * /----------------\ /----------------\ | * -// * | ann (Annual) | | dumy (basic) | | * -// * \----------------/ \----------------/ |-------------. * -// * 80 | Refers L--------------------------------. | | * -// * v Refers 80 v v 20 | * -// * /----------------\ /----------------\ | * -// * | scud (basic) |<------------------------| stud (basic) | | * -// * \----------------/ 20 Registers | (Upgrades to | | 5 * -// * | Lifetime) | v * -// * \----------------/ /--------------\ * -// * L------->| pleb (Basic) | * -// * 95 Refers \--------------/ * -// * * -// * Fee distribution chains (80-20 referral/net split, 50-30 referrer/LTM split) * -// * life : 80% -> life, 20% -> net * -// * rog: 80% -> rog, 20% -> net * -// * ann (before upg): 80% -> life, 20% -> net * -// * ann (after upg): 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% -> net * -// * stud (before upg): 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% * 80% -> rog, * -// * 20% -> net * -// * stud (after upg): 80% -> stud, 20% -> net * -// * dumy : 75% * 80% -> life, 25% * 80% -> rog, 20% -> net * -// * scud : 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% * 80% -> stud, 20% -> net * -// * pleb : 95% * 80% -> stud, 5% * 80% -> rog, 20% -> net * -// */ +BOOST_AUTO_TEST_CASE( cashback_test ) +{ try { + /* Account Structure used in this test * + * * + * /-----------------\ /-------------------\ * + * | life (Lifetime) | | rog (Lifetime) | * + * \-----------------/ \-------------------/ * + * | Ref&Reg | Refers | Registers | Registers * + * | | 75 | 25 | * + * v v v | * + * /----------------\ /----------------\ | * + * | ann (Annual) | | dumy (basic) | | * + * \----------------/ \----------------/ |-------------. * + * 80 | Refers L--------------------------------. | | * + * v Refers 80 v v 20 | * + * /----------------\ /----------------\ | * + * | scud (basic) |<------------------------| stud (basic) | | * + * \----------------/ 20 Registers | (Upgrades to | | 5 * + * | Lifetime) | v * + * \----------------/ /--------------\ * + * L------->| pleb (Basic) | * + * 95 Refers \--------------/ * + * * + * Fee distribution chains (80-20 referral/net split, 50-30 referrer/LTM split) * + * life : 80% -> life, 20% -> net * + * rog: 80% -> rog, 20% -> net * + * ann (before upg): 80% -> life, 20% -> net * + * ann (after upg): 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% -> net * + * stud (before upg): 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% * 80% -> rog, * + * 20% -> net * + * stud (after upg): 80% -> stud, 20% -> net * + * dumy : 75% * 80% -> life, 25% * 80% -> rog, 20% -> net * + * scud : 80% * 5/8 -> ann, 80% * 3/8 -> life, 20% * 80% -> stud, 20% -> net * + * pleb : 95% * 80% -> stud, 5% * 80% -> rog, 20% -> net * + */ -// BOOST_TEST_MESSAGE("Creating actors"); + BOOST_TEST_MESSAGE("Creating actors"); -// ACTOR(life); -// ACTOR(rog); -// PREP_ACTOR(ann); -// PREP_ACTOR(scud); -// PREP_ACTOR(dumy); -// PREP_ACTOR(stud); -// PREP_ACTOR(pleb); + ACTOR(life); + ACTOR(rog); + PREP_ACTOR(ann); + PREP_ACTOR(scud); + PREP_ACTOR(dumy); + PREP_ACTOR(stud); + PREP_ACTOR(pleb); -// account_id_type ann_id, scud_id, dumy_id, stud_id, pleb_id; -// actor_audit alife, arog, aann, ascud, adumy, astud, apleb; + account_id_type ann_id, scud_id, dumy_id, stud_id, pleb_id; + actor_audit alife, arog, aann, ascud, adumy, astud, apleb; -// alife.b0 = 100000000; -// arog.b0 = 100000000; -// aann.b0 = 1000000; -// astud.b0 = 1000000; -// astud.ref_pct = 80 * GRAPHENE_1_PERCENT; -// ascud.ref_pct = 80 * GRAPHENE_1_PERCENT; -// adumy.ref_pct = 75 * GRAPHENE_1_PERCENT; -// apleb.ref_pct = 95 * GRAPHENE_1_PERCENT; + alife.b0 = 100000000; + arog.b0 = 100000000; + aann.b0 = 1000000; + astud.b0 = 1000000; + astud.ref_pct = 80 * GRAPHENE_1_PERCENT; + ascud.ref_pct = 80 * GRAPHENE_1_PERCENT; + adumy.ref_pct = 75 * GRAPHENE_1_PERCENT; + apleb.ref_pct = 95 * GRAPHENE_1_PERCENT; -// transfer(account_id_type(), life_id, asset(alife.b0)); -// alife.bal += alife.b0; -// transfer(account_id_type(), rog_id, asset(arog.b0)); -// arog.bal += arog.b0; -// upgrade_to_lifetime_member(life_id); -// upgrade_to_lifetime_member(rog_id); + transfer(account_id_type(), life_id, asset(alife.b0)); + alife.bal += alife.b0; + transfer(account_id_type(), rog_id, asset(arog.b0)); + arog.bal += arog.b0; + upgrade_to_lifetime_member(life_id); + upgrade_to_lifetime_member(rog_id); -// BOOST_TEST_MESSAGE("Enable fees"); -// const auto& fees = db.get_global_properties().parameters.current_fees; + BOOST_TEST_MESSAGE("Enable fees"); + const auto& fees = db.get_global_properties().parameters.current_fees; -// #define CustomRegisterActor(actor_name, registrar_name, referrer_name, referrer_rate) \ -// { \ -// account_create_operation op; \ -// op.registrar = registrar_name ## _id; \ -// op.referrer = referrer_name ## _id; \ -// op.referrer_percent = referrer_rate*GRAPHENE_1_PERCENT; \ -// op.name = BOOST_PP_STRINGIZE(actor_name); \ -// op.options.memo_key = actor_name ## _private_key.get_public_key(); \ -// op.active = authority(1, public_key_type(actor_name ## _private_key.get_public_key()), 1); \ -// op.owner = op.active; \ -// op.fee = fees->calculate_fee(op); \ -// trx.operations = {op}; \ -// sign( trx, registrar_name ## _private_key ); \ -// actor_name ## _id = PUSH_TX( db, trx ).operation_results.front().get(); \ -// trx.clear(); \ -// } -// #define CustomAuditActor(actor_name) \ -// if( actor_name ## _id != account_id_type() ) \ -// { \ -// CHECK_BALANCE( actor_name, a ## actor_name.bal ); \ -// CHECK_VESTED_CASHBACK( actor_name, a ## actor_name.vcb ); \ -// CHECK_UNVESTED_CASHBACK( actor_name, a ## actor_name.ucb ); \ -// CHECK_CASHBACK_VBO( actor_name, a ## actor_name.ubal ); \ -// } +#define CustomRegisterActor(actor_name, registrar_name, referrer_name, referrer_rate) \ + { \ + account_create_operation op; \ + op.registrar = registrar_name ## _id; \ + op.referrer = referrer_name ## _id; \ + op.referrer_percent = referrer_rate*GRAPHENE_1_PERCENT; \ + op.name = BOOST_PP_STRINGIZE(actor_name); \ + op.options.memo_key = actor_name ## _private_key.get_public_key(); \ + op.active = authority(1, public_key_type(actor_name ## _private_key.get_public_key()), 1); \ + op.owner = op.active; \ + op.fee = fees->calculate_fee(op); \ + trx.operations = {op}; \ + sign( trx, registrar_name ## _private_key ); \ + actor_name ## _id = PUSH_TX( db, trx ).operation_results.front().get(); \ + trx.clear(); \ + } +#define CustomAuditActor(actor_name) \ + if( actor_name ## _id != account_id_type() ) \ + { \ + CHECK_BALANCE( actor_name, a ## actor_name.bal ); \ + CHECK_VESTED_CASHBACK( actor_name, a ## actor_name.vcb ); \ + CHECK_UNVESTED_CASHBACK( actor_name, a ## actor_name.ucb ); \ + CHECK_CASHBACK_VBO( actor_name, a ## actor_name.ubal ); \ + } -// #define CustomAudit() \ -// { \ -// CustomAuditActor( life ); \ -// CustomAuditActor( rog ); \ -// CustomAuditActor( ann ); \ -// CustomAuditActor( stud ); \ -// CustomAuditActor( dumy ); \ -// CustomAuditActor( scud ); \ -// CustomAuditActor( pleb ); \ -// } +#define CustomAudit() \ + { \ + CustomAuditActor( life ); \ + CustomAuditActor( rog ); \ + CustomAuditActor( ann ); \ + CustomAuditActor( stud ); \ + CustomAuditActor( dumy ); \ + CustomAuditActor( scud ); \ + CustomAuditActor( pleb ); \ + } -// int64_t reg_fee = fees->get< account_create_operation >().premium_fee; -// int64_t xfer_fee = fees->get< transfer_operation >().fee; -// int64_t upg_an_fee = fees->get< account_upgrade_operation >().membership_annual_fee; -// int64_t upg_lt_fee = fees->get< account_upgrade_operation >().membership_lifetime_fee; -// // all percentages here are cut from whole pie! -// uint64_t network_pct = 20 * P1; -// uint64_t lt_pct = 375 * P100 / 1000; + int64_t reg_fee = fees->get< account_create_operation >().premium_fee; + int64_t xfer_fee = fees->get< transfer_operation >().fee; + int64_t upg_an_fee = fees->get< account_upgrade_operation >().membership_annual_fee; + int64_t upg_lt_fee = fees->get< account_upgrade_operation >().membership_lifetime_fee; + // all percentages here are cut from whole pie! + uint64_t network_pct = 20 * P1; + uint64_t lt_pct = 375 * P100 / 1000; -// BOOST_TEST_MESSAGE("Register and upgrade Ann"); -// { -// CustomRegisterActor(ann, life, life, 75); -// alife.vcb += reg_fee; alife.bal += -reg_fee; -// CustomAudit(); + BOOST_TEST_MESSAGE("Register and upgrade Ann"); + { + CustomRegisterActor(ann, life, life, 75); + alife.vcb += reg_fee; alife.bal += -reg_fee; + CustomAudit(); -// transfer(life_id, ann_id, asset(aann.b0)); -// alife.vcb += xfer_fee; alife.bal += -xfer_fee -aann.b0; aann.bal += aann.b0; -// CustomAudit(); + transfer(life_id, ann_id, asset(aann.b0)); + alife.vcb += xfer_fee; alife.bal += -xfer_fee -aann.b0; aann.bal += aann.b0; + CustomAudit(); -// upgrade_to_annual_member(ann_id); -// aann.ucb += upg_an_fee; aann.bal += -upg_an_fee; + upgrade_to_annual_member(ann_id); + aann.ucb += upg_an_fee; aann.bal += -upg_an_fee; -// // audit distribution of fees from Ann -// alife.ubal += pct( P100-network_pct, aann.ucb ); -// alife.bal += pct( P100-network_pct, aann.vcb ); -// aann.ucb = 0; aann.vcb = 0; -// CustomAudit(); -// } + // audit distribution of fees from Ann + alife.ubal += pct( P100-network_pct, aann.ucb ); + alife.bal += pct( P100-network_pct, aann.vcb ); + aann.ucb = 0; aann.vcb = 0; + CustomAudit(); + } -// BOOST_TEST_MESSAGE("Register dumy and stud"); -// CustomRegisterActor(dumy, rog, life, 75); -// arog.vcb += reg_fee; arog.bal += -reg_fee; -// CustomAudit(); + BOOST_TEST_MESSAGE("Register dumy and stud"); + CustomRegisterActor(dumy, rog, life, 75); + arog.vcb += reg_fee; arog.bal += -reg_fee; + CustomAudit(); -// CustomRegisterActor(stud, rog, ann, 80); -// arog.vcb += reg_fee; arog.bal += -reg_fee; -// CustomAudit(); + CustomRegisterActor(stud, rog, ann, 80); + arog.vcb += reg_fee; arog.bal += -reg_fee; + CustomAudit(); -// BOOST_TEST_MESSAGE("Upgrade stud to lifetime member"); + BOOST_TEST_MESSAGE("Upgrade stud to lifetime member"); -// transfer(life_id, stud_id, asset(astud.b0)); -// alife.vcb += xfer_fee; alife.bal += -astud.b0 -xfer_fee; astud.bal += astud.b0; -// CustomAudit(); + transfer(life_id, stud_id, asset(astud.b0)); + alife.vcb += xfer_fee; alife.bal += -astud.b0 -xfer_fee; astud.bal += astud.b0; + CustomAudit(); -// upgrade_to_lifetime_member(stud_id); -// astud.ucb += upg_lt_fee; astud.bal -= upg_lt_fee; + upgrade_to_lifetime_member(stud_id); + astud.ucb += upg_lt_fee; astud.bal -= upg_lt_fee; -// /* -// network_cut: 20000 -// referrer_cut: 40000 -> ann -// registrar_cut: 10000 -> rog -// lifetime_cut: 30000 -> life +/* +network_cut: 20000 +referrer_cut: 40000 -> ann +registrar_cut: 10000 -> rog +lifetime_cut: 30000 -> life -// NET : net -// LTM : net' ltm -// REF : net' ltm' ref -// REG : net' ltm' ref' -// */ +NET : net +LTM : net' ltm +REF : net' ltm' ref +REG : net' ltm' ref' +*/ -// // audit distribution of fees from stud -// alife.ubal += pct( P100-network_pct, lt_pct, astud.ucb ); -// aann.ubal += pct( P100-network_pct, P100-lt_pct, astud.ref_pct, astud.ucb ); -// arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-astud.ref_pct, astud.ucb ); -// astud.ucb = 0; -// CustomAudit(); + // audit distribution of fees from stud + alife.ubal += pct( P100-network_pct, lt_pct, astud.ucb ); + aann.ubal += pct( P100-network_pct, P100-lt_pct, astud.ref_pct, astud.ucb ); + arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-astud.ref_pct, astud.ucb ); + astud.ucb = 0; + CustomAudit(); -// BOOST_TEST_MESSAGE("Register pleb and scud"); + BOOST_TEST_MESSAGE("Register pleb and scud"); -// CustomRegisterActor(pleb, rog, stud, 95); -// arog.vcb += reg_fee; arog.bal += -reg_fee; -// CustomAudit(); + CustomRegisterActor(pleb, rog, stud, 95); + arog.vcb += reg_fee; arog.bal += -reg_fee; + CustomAudit(); -// CustomRegisterActor(scud, stud, ann, 80); -// astud.vcb += reg_fee; astud.bal += -reg_fee; -// CustomAudit(); + CustomRegisterActor(scud, stud, ann, 80); + astud.vcb += reg_fee; astud.bal += -reg_fee; + CustomAudit(); -// generate_block(); + generate_block(); -// BOOST_TEST_MESSAGE("Wait for maintenance interval"); + BOOST_TEST_MESSAGE("Wait for maintenance interval"); -// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); -// // audit distribution of fees from life -// alife.ubal += pct( P100-network_pct, alife.ucb +alife.vcb ); -// alife.ucb = 0; alife.vcb = 0; + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + // audit distribution of fees from life + alife.ubal += pct( P100-network_pct, alife.ucb +alife.vcb ); + alife.ucb = 0; alife.vcb = 0; -// // audit distribution of fees from rog -// arog.ubal += pct( P100-network_pct, arog.ucb + arog.vcb ); -// arog.ucb = 0; arog.vcb = 0; + // audit distribution of fees from rog + arog.ubal += pct( P100-network_pct, arog.ucb + arog.vcb ); + arog.ucb = 0; arog.vcb = 0; -// // audit distribution of fees from ann -// alife.ubal += pct( P100-network_pct, lt_pct, aann.ucb+aann.vcb ); -// aann.ubal += pct( P100-network_pct, P100-lt_pct, aann.ref_pct, aann.ucb+aann.vcb ); -// alife.ubal += pct( P100-network_pct, P100-lt_pct, P100-aann.ref_pct, aann.ucb+aann.vcb ); -// aann.ucb = 0; aann.vcb = 0; + // audit distribution of fees from ann + alife.ubal += pct( P100-network_pct, lt_pct, aann.ucb+aann.vcb ); + aann.ubal += pct( P100-network_pct, P100-lt_pct, aann.ref_pct, aann.ucb+aann.vcb ); + alife.ubal += pct( P100-network_pct, P100-lt_pct, P100-aann.ref_pct, aann.ucb+aann.vcb ); + aann.ucb = 0; aann.vcb = 0; -// // audit distribution of fees from stud -// astud.ubal += pct( P100-network_pct, astud.ucb+astud.vcb ); -// astud.ucb = 0; astud.vcb = 0; + // audit distribution of fees from stud + astud.ubal += pct( P100-network_pct, astud.ucb+astud.vcb ); + astud.ucb = 0; astud.vcb = 0; -// // audit distribution of fees from dumy -// alife.ubal += pct( P100-network_pct, lt_pct, adumy.ucb+adumy.vcb ); -// alife.ubal += pct( P100-network_pct, P100-lt_pct, adumy.ref_pct, adumy.ucb+adumy.vcb ); -// arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-adumy.ref_pct, adumy.ucb+adumy.vcb ); -// adumy.ucb = 0; adumy.vcb = 0; + // audit distribution of fees from dumy + alife.ubal += pct( P100-network_pct, lt_pct, adumy.ucb+adumy.vcb ); + alife.ubal += pct( P100-network_pct, P100-lt_pct, adumy.ref_pct, adumy.ucb+adumy.vcb ); + arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-adumy.ref_pct, adumy.ucb+adumy.vcb ); + adumy.ucb = 0; adumy.vcb = 0; -// // audit distribution of fees from scud -// alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); -// aann.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); -// astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); -// ascud.ucb = 0; ascud.vcb = 0; + // audit distribution of fees from scud + alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); + aann.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); + astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); + ascud.ucb = 0; ascud.vcb = 0; -// // audit distribution of fees from pleb -// astud.ubal += pct( P100-network_pct, lt_pct, apleb.ucb+apleb.vcb ); -// astud.ubal += pct( P100-network_pct, P100-lt_pct, apleb.ref_pct, apleb.ucb+apleb.vcb ); -// arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-apleb.ref_pct, apleb.ucb+apleb.vcb ); -// apleb.ucb = 0; apleb.vcb = 0; + // audit distribution of fees from pleb + astud.ubal += pct( P100-network_pct, lt_pct, apleb.ucb+apleb.vcb ); + astud.ubal += pct( P100-network_pct, P100-lt_pct, apleb.ref_pct, apleb.ucb+apleb.vcb ); + arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-apleb.ref_pct, apleb.ucb+apleb.vcb ); + apleb.ucb = 0; apleb.vcb = 0; -// CustomAudit(); + CustomAudit(); -// BOOST_TEST_MESSAGE("Doing some transfers"); + BOOST_TEST_MESSAGE("Doing some transfers"); -// transfer(stud_id, scud_id, asset(500000)); -// astud.bal += -500000-xfer_fee; astud.vcb += xfer_fee; ascud.bal += 500000; -// CustomAudit(); + transfer(stud_id, scud_id, asset(500000)); + astud.bal += -500000-xfer_fee; astud.vcb += xfer_fee; ascud.bal += 500000; + CustomAudit(); -// transfer(scud_id, pleb_id, asset(400000)); -// ascud.bal += -400000-xfer_fee; ascud.vcb += xfer_fee; apleb.bal += 400000; -// CustomAudit(); + transfer(scud_id, pleb_id, asset(400000)); + ascud.bal += -400000-xfer_fee; ascud.vcb += xfer_fee; apleb.bal += 400000; + CustomAudit(); -// transfer(pleb_id, dumy_id, asset(300000)); -// apleb.bal += -300000-xfer_fee; apleb.vcb += xfer_fee; adumy.bal += 300000; -// CustomAudit(); + transfer(pleb_id, dumy_id, asset(300000)); + apleb.bal += -300000-xfer_fee; apleb.vcb += xfer_fee; adumy.bal += 300000; + CustomAudit(); -// transfer(dumy_id, rog_id, asset(200000)); -// adumy.bal += -200000-xfer_fee; adumy.vcb += xfer_fee; arog.bal += 200000; -// CustomAudit(); + transfer(dumy_id, rog_id, asset(200000)); + adumy.bal += -200000-xfer_fee; adumy.vcb += xfer_fee; arog.bal += 200000; + CustomAudit(); -// BOOST_TEST_MESSAGE("Waiting for maintenance time"); + BOOST_TEST_MESSAGE("Waiting for maintenance time"); -// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); -// // audit distribution of fees from life -// alife.ubal += pct( P100-network_pct, alife.ucb +alife.vcb ); -// alife.ucb = 0; alife.vcb = 0; + // audit distribution of fees from life + alife.ubal += pct( P100-network_pct, alife.ucb +alife.vcb ); + alife.ucb = 0; alife.vcb = 0; -// // audit distribution of fees from rog -// arog.ubal += pct( P100-network_pct, arog.ucb + arog.vcb ); -// arog.ucb = 0; arog.vcb = 0; + // audit distribution of fees from rog + arog.ubal += pct( P100-network_pct, arog.ucb + arog.vcb ); + arog.ucb = 0; arog.vcb = 0; -// // audit distribution of fees from ann -// alife.ubal += pct( P100-network_pct, lt_pct, aann.ucb+aann.vcb ); -// aann.ubal += pct( P100-network_pct, P100-lt_pct, aann.ref_pct, aann.ucb+aann.vcb ); -// alife.ubal += pct( P100-network_pct, P100-lt_pct, P100-aann.ref_pct, aann.ucb+aann.vcb ); -// aann.ucb = 0; aann.vcb = 0; + // audit distribution of fees from ann + alife.ubal += pct( P100-network_pct, lt_pct, aann.ucb+aann.vcb ); + aann.ubal += pct( P100-network_pct, P100-lt_pct, aann.ref_pct, aann.ucb+aann.vcb ); + alife.ubal += pct( P100-network_pct, P100-lt_pct, P100-aann.ref_pct, aann.ucb+aann.vcb ); + aann.ucb = 0; aann.vcb = 0; -// // audit distribution of fees from stud -// astud.ubal += pct( P100-network_pct, astud.ucb+astud.vcb ); -// astud.ucb = 0; astud.vcb = 0; + // audit distribution of fees from stud + astud.ubal += pct( P100-network_pct, astud.ucb+astud.vcb ); + astud.ucb = 0; astud.vcb = 0; -// // audit distribution of fees from dumy -// alife.ubal += pct( P100-network_pct, lt_pct, adumy.ucb+adumy.vcb ); -// alife.ubal += pct( P100-network_pct, P100-lt_pct, adumy.ref_pct, adumy.ucb+adumy.vcb ); -// arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-adumy.ref_pct, adumy.ucb+adumy.vcb ); -// adumy.ucb = 0; adumy.vcb = 0; + // audit distribution of fees from dumy + alife.ubal += pct( P100-network_pct, lt_pct, adumy.ucb+adumy.vcb ); + alife.ubal += pct( P100-network_pct, P100-lt_pct, adumy.ref_pct, adumy.ucb+adumy.vcb ); + arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-adumy.ref_pct, adumy.ucb+adumy.vcb ); + adumy.ucb = 0; adumy.vcb = 0; -// // audit distribution of fees from scud -// alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); -// aann.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); -// astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); -// ascud.ucb = 0; ascud.vcb = 0; + // audit distribution of fees from scud + alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); + aann.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); + astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); + ascud.ucb = 0; ascud.vcb = 0; -// // audit distribution of fees from pleb -// astud.ubal += pct( P100-network_pct, lt_pct, apleb.ucb+apleb.vcb ); -// astud.ubal += pct( P100-network_pct, P100-lt_pct, apleb.ref_pct, apleb.ucb+apleb.vcb ); -// arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-apleb.ref_pct, apleb.ucb+apleb.vcb ); -// apleb.ucb = 0; apleb.vcb = 0; + // audit distribution of fees from pleb + astud.ubal += pct( P100-network_pct, lt_pct, apleb.ucb+apleb.vcb ); + astud.ubal += pct( P100-network_pct, P100-lt_pct, apleb.ref_pct, apleb.ucb+apleb.vcb ); + arog.ubal += pct( P100-network_pct, P100-lt_pct, P100-apleb.ref_pct, apleb.ucb+apleb.vcb ); + apleb.ucb = 0; apleb.vcb = 0; -// CustomAudit(); + CustomAudit(); -// BOOST_TEST_MESSAGE("Waiting for annual membership to expire"); + BOOST_TEST_MESSAGE("Waiting for annual membership to expire"); + BOOST_TEST_MESSAGE("Count of block to generate " + std::to_string(ann_id(db).membership_expiration_date.sec_since_epoch())); -// generate_blocks(ann_id(db).membership_expiration_date); -// generate_block(); + generate_blocks(ann_id(db).membership_expiration_date); + generate_block(); -// BOOST_TEST_MESSAGE("Transferring from scud to pleb"); + BOOST_TEST_MESSAGE("Transferring from scud to pleb"); -// //ann's membership has expired, so scud's fee should go up to life instead. -// transfer(scud_id, pleb_id, asset(10)); -// ascud.bal += -10-xfer_fee; ascud.vcb += xfer_fee; apleb.bal += 10; -// CustomAudit(); + //ann's membership has expired, so scud's fee should go up to life instead. + transfer(scud_id, pleb_id, asset(10)); + ascud.bal += -10-xfer_fee; ascud.vcb += xfer_fee; apleb.bal += 10; + CustomAudit(); -// BOOST_TEST_MESSAGE("Waiting for maint interval"); + BOOST_TEST_MESSAGE("Waiting for maint interval"); -// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); -// // audit distribution of fees from scud -// alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); -// alife.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); -// astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); -// ascud.ucb = 0; ascud.vcb = 0; + // audit distribution of fees from scud + alife.ubal += pct( P100-network_pct, lt_pct, ascud.ucb+ascud.vcb ); + alife.ubal += pct( P100-network_pct, P100-lt_pct, ascud.ref_pct, ascud.ucb+ascud.vcb ); + astud.ubal += pct( P100-network_pct, P100-lt_pct, P100-ascud.ref_pct, ascud.ucb+ascud.vcb ); + ascud.ucb = 0; ascud.vcb = 0; -// CustomAudit(); + CustomAudit(); -// } FC_LOG_AND_RETHROW() } +} FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_CASE( account_create_fee_scaling ) { try { @@ -1033,7 +1036,6 @@ BOOST_AUTO_TEST_CASE( issue_429_test ) verify_asset_supplies( db ); - generate_blocks( HARDFORK_CORE_429_TIME + 10 ); { signed_transaction tx; asset_create_operation op; @@ -1046,7 +1048,7 @@ BOOST_AUTO_TEST_CASE( issue_429_test ) sign( tx, alice_private_key ); PUSH_TX( db, tx ); } - + verify_asset_supplies( db ); } catch( const fc::exception& e ) diff --git a/tests/tests/network_broadcast_api_tests.cpp b/tests/tests/network_broadcast_api_tests.cpp index 50fb1715..a0d2082d 100644 --- a/tests/tests/network_broadcast_api_tests.cpp +++ b/tests/tests/network_broadcast_api_tests.cpp @@ -99,8 +99,7 @@ BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_tw create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -153,8 +152,7 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplication_in_transaction_with_several_op auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)), make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -174,8 +172,7 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)), make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -194,8 +191,7 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -229,8 +225,7 @@ BOOST_AUTO_TEST_CASE( check_fails_for_same_member_create_operations ) create_proposal(*this, {make_committee_member_create_operation(asset(1000), account_id_type(), "test url")}); auto trx = make_signed_transaction_with_proposed_operation(*this, {make_committee_member_create_operation(asset(1000), account_id_type(), "test url")}); - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -269,9 +264,7 @@ BOOST_AUTO_TEST_CASE( check_failes_for_several_operations_of_mixed_type ) auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)), //duplicate make_committee_member_create_operation(asset(1002), account_id_type(), "test url")}); - - //Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes - BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { diff --git a/tests/tests/operation_tests.cpp b/tests/tests/operation_tests.cpp index 50b1fd0c..6de27437 100644 --- a/tests/tests/operation_tests.cpp +++ b/tests/tests/operation_tests.cpp @@ -1112,6 +1112,633 @@ BOOST_AUTO_TEST_CASE( uia_fees ) } } +BOOST_FIXTURE_TEST_SUITE( dividend_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE( create_dividend_uia ) +{ + using namespace graphene; + try { + BOOST_TEST_MESSAGE("Creating dividend holder asset"); + { + asset_create_operation creator; + creator.issuer = account_id_type(); + creator.fee = asset(); + creator.symbol = "DIVIDEND"; + creator.common_options.max_supply = 100000000; + creator.precision = 2; + creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/ + creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + creator.common_options.flags = charge_market_fee; + creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))}); + trx.operations.push_back(std::move(creator)); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + + BOOST_TEST_MESSAGE("Creating test accounts"); + create_account("alice"); + create_account("bob"); + create_account("carol"); + create_account("dave"); + create_account("frank"); + + BOOST_TEST_MESSAGE("Creating test asset"); + { + asset_create_operation creator; + creator.issuer = account_id_type(); + creator.fee = asset(); + creator.symbol = "TEST"; + creator.common_options.max_supply = 100000000; + creator.precision = 2; + creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/ + creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + creator.common_options.flags = charge_market_fee; + creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))}); + trx.operations.push_back(std::move(creator)); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + + BOOST_TEST_MESSAGE("Funding asset fee pool"); + { + asset_fund_fee_pool_operation fund_op; + fund_op.from_account = account_id_type(); + fund_op.asset_id = get_asset("TEST").id; + fund_op.amount = 500000000; + trx.operations.push_back(std::move(fund_op)); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + + // our DIVIDEND asset should not yet be a divdend asset + const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); + BOOST_CHECK(!dividend_holder_asset_object.dividend_data_id); + + BOOST_TEST_MESSAGE("Converting the new asset to a dividend holder asset"); + { + asset_update_dividend_operation op; + op.issuer = dividend_holder_asset_object.issuer; + op.asset_to_update = dividend_holder_asset_object.id; + op.new_options.next_payout_time = db.head_block_time() + fc::minutes(1); + op.new_options.payout_interval = 60 * 60 * 24 * 3; + + trx.operations.push_back(op); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + + BOOST_TEST_MESSAGE("Verifying the dividend holder asset options"); + BOOST_REQUIRE(dividend_holder_asset_object.dividend_data_id); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + { + BOOST_REQUIRE(dividend_data.options.payout_interval); + BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24 * 3); + } + + const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); + BOOST_CHECK_EQUAL(dividend_distribution_account.name, "dividend-dividend-distribution"); + + // db.modify( db.get_global_properties(), [&]( global_property_object& _gpo ) + // { + // _gpo.parameters.current_fees->get().distribution_base_fee = 100; + // _gpo.parameters.current_fees->get().distribution_fee_per_holder = 100; + // } ); + + + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( test_update_dividend_interval ) +{ + using namespace graphene; + try { + INVOKE( create_dividend_uia ); + + const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + + auto advance_to_next_payout_time = [&]() { + // Advance to the next upcoming payout time + BOOST_REQUIRE(dividend_data.options.next_payout_time); + fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time; + // generate blocks up to the next scheduled time + generate_blocks(next_payout_scheduled_time); + // if the scheduled time fell on a maintenance interval, then we should have paid out. + // if not, we need to advance to the next maintenance interval to trigger the payout + if (dividend_data.options.next_payout_time) + { + // we know there was a next_payout_time set when we entered this, so if + // it has been cleared, we must have already processed payouts, no need to + // further advance time. + BOOST_REQUIRE(dividend_data.options.next_payout_time); + if (*dividend_data.options.next_payout_time == next_payout_scheduled_time) + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + } + }; + + BOOST_TEST_MESSAGE("Updating the payout interval"); + { + asset_update_dividend_operation op; + op.issuer = dividend_holder_asset_object.issuer; + op.asset_to_update = dividend_holder_asset_object.id; + op.new_options.next_payout_time = fc::time_point::now() + fc::minutes(1); + op.new_options.payout_interval = 60 * 60 * 24; // 1 days + trx.operations.push_back(op); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + + BOOST_TEST_MESSAGE("Verifying the updated dividend holder asset options"); + { + BOOST_REQUIRE(dividend_data.options.payout_interval); + BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24); + } + + BOOST_TEST_MESSAGE("Removing the payout interval"); + { + asset_update_dividend_operation op; + op.issuer = dividend_holder_asset_object.issuer; + op.asset_to_update = dividend_holder_asset_object.id; + op.new_options.next_payout_time = dividend_data.options.next_payout_time; + op.new_options.payout_interval = fc::optional(); + trx.operations.push_back(op); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + BOOST_CHECK(!dividend_data.options.payout_interval); + advance_to_next_payout_time(); + BOOST_REQUIRE_MESSAGE(!dividend_data.options.next_payout_time, "A new payout was scheduled, but none should have been"); + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution ) +{ + using namespace graphene; + try { + INVOKE( create_dividend_uia ); + + const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); + const account_object& alice = get_account("alice"); + const account_object& bob = get_account("bob"); + const account_object& carol = get_account("carol"); + const account_object& dave = get_account("dave"); + const account_object& frank = get_account("frank"); + const auto& test_asset_object = get_asset("TEST"); + + auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) + { + asset_issue_operation op; + op.issuer = asset_to_issue.issuer; + op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id); + op.issue_to_account = destination_account.id; + trx.operations.push_back( op ); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + }; + + auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) { + int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id, + holder_account_obj.id, + payout_asset_obj.id); + BOOST_CHECK_EQUAL(pending_balance, expected_balance); + }; + + auto advance_to_next_payout_time = [&]() { + // Advance to the next upcoming payout time + BOOST_REQUIRE(dividend_data.options.next_payout_time); + fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time; + // generate blocks up to the next scheduled time + generate_blocks(next_payout_scheduled_time); + // if the scheduled time fell on a maintenance interval, then we should have paid out. + // if not, we need to advance to the next maintenance interval to trigger the payout + if (dividend_data.options.next_payout_time) + { + // we know there was a next_payout_time set when we entered this, so if + // it has been cleared, we must have already processed payouts, no need to + // further advance time. + BOOST_REQUIRE(dividend_data.options.next_payout_time); + if (*dividend_data.options.next_payout_time == next_payout_scheduled_time) + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + } + }; + + // the first test will be testing pending balances, so we need to hit a + // maintenance interval that isn't the payout interval. Payout is + // every 3 days, maintenance interval is every 1 day. + advance_to_next_payout_time(); + + // Set up the first test, issue alice, bob, and carol each 100 DIVIDEND. + // Then deposit 300 TEST in the distribution account, and see that they + // each are credited 100 TEST. + issue_asset_to_account(dividend_holder_asset_object, alice, 100000); + issue_asset_to_account(dividend_holder_asset_object, bob, 100000); + issue_asset_to_account(dividend_holder_asset_object, carol, 100000); + + BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account"); + issue_asset_to_account(test_asset_object, dividend_distribution_account, 30000); + + generate_block(); + + BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" ); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + + verify_pending_balance(alice, test_asset_object, 10000); + verify_pending_balance(bob, test_asset_object, 10000); + verify_pending_balance(carol, test_asset_object, 10000); + + // For the second test, issue carol more than the other two, so it's + // alice: 100 DIVIDND, bob: 100 DIVIDEND, carol: 200 DIVIDEND + // Then deposit 400 TEST in the distribution account, and see that alice + // and bob are credited with 100 TEST, and carol gets 200 TEST + BOOST_TEST_MESSAGE("Issuing carol twice as much of the holder asset"); + issue_asset_to_account(dividend_holder_asset_object, carol, 100000); // one thousand at two digits of precision + issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000); // one thousand at two digits of precision + BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" ); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + verify_pending_balance(alice, test_asset_object, 20000); + verify_pending_balance(bob, test_asset_object, 20000); + verify_pending_balance(carol, test_asset_object, 30000); + + fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time; + advance_to_next_payout_time(); + + + BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled"); + BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time, + "New payout was scheduled for the same time as the last payout"); + BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time, + "New payout was not scheduled for the expected time"); + + auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout) + { + BOOST_TEST_MESSAGE("Verifying the virtual op was created"); + const account_transaction_history_index& hist_idx = db.get_index_type(); + auto account_history_range = hist_idx.indices().get().equal_range(boost::make_tuple(destination_account.id)); + BOOST_REQUIRE(account_history_range.first != account_history_range.second); + const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db); + const asset_dividend_distribution_operation& distribution_operation = history_object.op.get(); + BOOST_CHECK(distribution_operation.account_id == destination_account.id); + BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout) + != distribution_operation.amounts.end()); + }; + + BOOST_TEST_MESSAGE("Verifying the payouts"); + BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000); + verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id)); + verify_pending_balance(alice, test_asset_object, 0); + + BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000); + verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id)); + verify_pending_balance(bob, test_asset_object, 0); + + BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 30000); + verify_dividend_payout_operations(carol, asset(30000, test_asset_object.id)); + verify_pending_balance(carol, test_asset_object, 0); + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution_to_core_asset ) +{ + using namespace graphene; + try { + BOOST_TEST_MESSAGE("Creating test accounts"); + create_account("alice"); + create_account("bob"); + create_account("carol"); + create_account("dave"); + create_account("frank"); + + BOOST_TEST_MESSAGE("Creating test asset"); + { + asset_create_operation creator; + creator.issuer = account_id_type(); + creator.fee = asset(); + creator.symbol = "TEST"; + creator.common_options.max_supply = 100000000; + creator.precision = 2; + creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/ + creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + creator.common_options.flags = charge_market_fee; + creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))}); + trx.operations.push_back(std::move(creator)); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + } + generate_block(); + + const auto& dividend_holder_asset_object = asset_id_type(0)(db); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); + const account_object& alice = get_account("alice"); + const account_object& bob = get_account("bob"); + const account_object& carol = get_account("carol"); + const account_object& dave = get_account("dave"); + const account_object& frank = get_account("frank"); + const auto& test_asset_object = get_asset("TEST"); + + auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) + { + asset_issue_operation op; + op.issuer = asset_to_issue.issuer; + op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id); + op.issue_to_account = destination_account.id; + trx.operations.push_back( op ); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + }; + + auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) { + int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id, + holder_account_obj.id, + payout_asset_obj.id); + BOOST_CHECK_EQUAL(pending_balance, expected_balance); + }; + + auto advance_to_next_payout_time = [&]() { + // Advance to the next upcoming payout time + BOOST_REQUIRE(dividend_data.options.next_payout_time); + fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time; + idump((next_payout_scheduled_time)); + // generate blocks up to the next scheduled time + generate_blocks(next_payout_scheduled_time); + // if the scheduled time fell on a maintenance interval, then we should have paid out. + // if not, we need to advance to the next maintenance interval to trigger the payout + if (dividend_data.options.next_payout_time) + { + // we know there was a next_payout_time set when we entered this, so if + // it has been cleared, we must have already processed payouts, no need to + // further advance time. + BOOST_REQUIRE(dividend_data.options.next_payout_time); + if (*dividend_data.options.next_payout_time == next_payout_scheduled_time) + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + } + idump((db.head_block_time())); + }; + + // the first test will be testing pending balances, so we need to hit a + // maintenance interval that isn't the payout interval. Payout is + // every 3 days, maintenance interval is every 1 day. + advance_to_next_payout_time(); + + // Set up the first test, issue alice, bob, and carol, and dave each 1/4 of the total + // supply of the core asset. + // Then deposit 400 TEST in the distribution account, and see that they + // each are credited 100 TEST. + transfer( committee_account(db), alice, asset( 250000000000000 ) ); + transfer( committee_account(db), bob, asset( 250000000000000 ) ); + transfer( committee_account(db), carol, asset( 250000000000000 ) ); + transfer( committee_account(db), dave, asset( 250000000000000 ) ); + + BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account"); + issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000); + + generate_block(); + + BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" ); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + + verify_pending_balance(alice, test_asset_object, 10000); + verify_pending_balance(bob, test_asset_object, 10000); + verify_pending_balance(carol, test_asset_object, 10000); + verify_pending_balance(dave, test_asset_object, 10000); + + // For the second test, issue dave more than the other two, so it's + // alice: 1/5 CORE, bob: 1/5 CORE, carol: 1/5 CORE, dave: 2/5 CORE + // Then deposit 500 TEST in the distribution account, and see that alice + // bob, and carol are credited with 100 TEST, and dave gets 200 TEST + BOOST_TEST_MESSAGE("Issuing dave twice as much of the holder asset"); + transfer( alice, dave, asset( 50000000000000 ) ); + transfer( bob, dave, asset( 50000000000000 ) ); + transfer( carol, dave, asset( 50000000000000 ) ); + issue_asset_to_account(test_asset_object, dividend_distribution_account, 50000); // 500 at two digits of precision + BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" ); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + verify_pending_balance(alice, test_asset_object, 20000); + verify_pending_balance(bob, test_asset_object, 20000); + verify_pending_balance(carol, test_asset_object, 20000); + verify_pending_balance(dave, test_asset_object, 30000); + + fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time; + advance_to_next_payout_time(); + + + BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled"); + BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time, + "New payout was scheduled for the same time as the last payout"); + BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time, + "New payout was not scheduled for the expected time"); + + auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout) + { + BOOST_TEST_MESSAGE("Verifying the virtual op was created"); + const account_transaction_history_index& hist_idx = db.get_index_type(); + auto account_history_range = hist_idx.indices().get().equal_range(boost::make_tuple(destination_account.id)); + BOOST_REQUIRE(account_history_range.first != account_history_range.second); + const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db); + const asset_dividend_distribution_operation& distribution_operation = history_object.op.get(); + BOOST_CHECK(distribution_operation.account_id == destination_account.id); + BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout) + != distribution_operation.amounts.end()); + }; + + BOOST_TEST_MESSAGE("Verifying the payouts"); + BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000); + verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id)); + verify_pending_balance(alice, test_asset_object, 0); + + BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000); + verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id)); + verify_pending_balance(bob, test_asset_object, 0); + + BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 20000); + verify_dividend_payout_operations(carol, asset(20000, test_asset_object.id)); + verify_pending_balance(carol, test_asset_object, 0); + + BOOST_CHECK_EQUAL(get_balance(dave, test_asset_object), 30000); + verify_dividend_payout_operations(dave, asset(30000, test_asset_object.id)); + verify_pending_balance(dave, test_asset_object, 0); + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( test_dividend_distribution_interval ) +{ + using namespace graphene; + try { + INVOKE( create_dividend_uia ); + + const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); + const account_object& alice = get_account("alice"); + const account_object& bob = get_account("bob"); + const account_object& carol = get_account("carol"); + const account_object& dave = get_account("dave"); + const account_object& frank = get_account("frank"); + const auto& test_asset_object = get_asset("TEST"); + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + + +BOOST_AUTO_TEST_CASE( check_dividend_corner_cases ) +{ + using namespace graphene; + try { + INVOKE( create_dividend_uia ); + + const auto& dividend_holder_asset_object = get_asset("DIVIDEND"); + const auto& dividend_data = dividend_holder_asset_object.dividend_data(db); + const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db); + const account_object& alice = get_account("alice"); + const account_object& bob = get_account("bob"); + const account_object& carol = get_account("carol"); + const account_object& dave = get_account("dave"); + const account_object& frank = get_account("frank"); + const auto& test_asset_object = get_asset("TEST"); + + auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue) + { + asset_issue_operation op; + op.issuer = asset_to_issue.issuer; + op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id); + op.issue_to_account = destination_account.id; + trx.operations.push_back( op ); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + }; + + auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) { + int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id, + holder_account_obj.id, + payout_asset_obj.id); + BOOST_CHECK_EQUAL(pending_balance, expected_balance); + }; + + auto reserve_asset_from_account = [&](const asset_object& asset_to_reserve, const account_object& from_account, int64_t amount_to_reserve) + { + asset_reserve_operation reserve_op; + reserve_op.payer = from_account.id; + reserve_op.amount_to_reserve = asset(amount_to_reserve, asset_to_reserve.id); + trx.operations.push_back(reserve_op); + set_expiration(db, trx); + PUSH_TX( db, trx, ~0 ); + trx.operations.clear(); + }; + auto advance_to_next_payout_time = [&]() { + // Advance to the next upcoming payout time + BOOST_REQUIRE(dividend_data.options.next_payout_time); + fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time; + // generate blocks up to the next scheduled time + generate_blocks(next_payout_scheduled_time); + // if the scheduled time fell on a maintenance interval, then we should have paid out. + // if not, we need to advance to the next maintenance interval to trigger the payout + if (dividend_data.options.next_payout_time) + { + // we know there was a next_payout_time set when we entered this, so if + // it has been cleared, we must have already processed payouts, no need to + // further advance time. + BOOST_REQUIRE(dividend_data.options.next_payout_time); + if (*dividend_data.options.next_payout_time == next_payout_scheduled_time) + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + } + }; + + // the first test will be testing pending balances, so we need to hit a + // maintenance interval that isn't the payout interval. Payout is + // every 3 days, maintenance interval is every 1 day. + advance_to_next_payout_time(); + + BOOST_TEST_MESSAGE("Testing a payout interval when there are no users holding the dividend asset"); + BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0); + BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0); + BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0); + issue_asset_to_account(test_asset_object, dividend_distribution_account, 1000); + BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval"); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + BOOST_TEST_MESSAGE("Verify that no pending payments were scheduled"); + verify_pending_balance(alice, test_asset_object, 0); + verify_pending_balance(bob, test_asset_object, 0); + verify_pending_balance(carol, test_asset_object, 0); + advance_to_next_payout_time(); + BOOST_TEST_MESSAGE("Verify that no actual payments took place"); + verify_pending_balance(alice, test_asset_object, 0); + verify_pending_balance(bob, test_asset_object, 0); + verify_pending_balance(carol, test_asset_object, 0); + BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 0); + BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 0); + BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 0); + BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, test_asset_object), 1000); + + BOOST_TEST_MESSAGE("Now give alice a small balance and see that she takes it all"); + issue_asset_to_account(dividend_holder_asset_object, alice, 1); + generate_block(); + BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval"); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + BOOST_TEST_MESSAGE("Verify that no alice received her payment of the entire amount"); + verify_pending_balance(alice, test_asset_object, 1000); + + // Test that we can pay out the dividend asset itself + issue_asset_to_account(dividend_holder_asset_object, bob, 1); + issue_asset_to_account(dividend_holder_asset_object, carol, 1); + issue_asset_to_account(dividend_holder_asset_object, dividend_distribution_account, 300); + generate_block(); + BOOST_CHECK_EQUAL(get_balance(alice, dividend_holder_asset_object), 1); + BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 1); + BOOST_CHECK_EQUAL(get_balance(carol, dividend_holder_asset_object), 1); + BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval"); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); // get the maintenance skip slots out of the way + BOOST_TEST_MESSAGE("Verify that the dividend asset was shared out"); + verify_pending_balance(alice, dividend_holder_asset_object, 100); + verify_pending_balance(bob, dividend_holder_asset_object, 100); + verify_pending_balance(carol, dividend_holder_asset_object, 100); + } catch(fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_SUITE_END() // end dividend_tests suite + BOOST_AUTO_TEST_CASE( cancel_limit_order_test ) { try { INVOKE( issue_uia ); diff --git a/tests/tests/operation_tests2.cpp b/tests/tests/operation_tests2.cpp index 07f93fd9..12262fa7 100644 --- a/tests/tests/operation_tests2.cpp +++ b/tests/tests/operation_tests2.cpp @@ -1400,7 +1400,6 @@ BOOST_AUTO_TEST_CASE( vbo_withdraw_different ) create_op.owner = alice_id; create_op.amount = asset(100, stuff_id); create_op.policy = pinit; - create_op.balance_type = vesting_balance_type::unspecified; signed_transaction create_tx; create_tx.operations.push_back( create_op );