#include #include #include #include #include #include #include #include #include #include #include #include #include "../common/database_fixture.hpp" using namespace graphene::chain; using namespace graphene::chain::test; namespace { transfer_operation make_transfer_operation(const account_id_type& from, const account_id_type& to, const asset& amount) { transfer_operation transfer; transfer.from = from; transfer.to = to; transfer.amount = amount; return transfer; } committee_member_create_operation make_committee_member_create_operation(const asset& fee, const account_id_type& member, const string& url) { committee_member_create_operation member_create_operation; member_create_operation.fee = fee; member_create_operation.committee_member_account = member; member_create_operation.url = url; return member_create_operation; } void create_proposal(database_fixture& fixture, const std::vector& operations) { signed_transaction transaction; set_expiration(fixture.db, transaction); transaction.operations = operations; fixture.db.create([&](proposal_object& proposal) { proposal.proposed_transaction = transaction; }); } signed_transaction make_signed_transaction_with_proposed_operation(database_fixture& fixture, const std::vector& operations) { proposal_create_operation operation_proposal; for (auto& operation: operations) { operation_proposal.proposed_ops.push_back(op_wrapper(operation)); } signed_transaction transaction; set_expiration(fixture.db, transaction); transaction.operations = {operation_proposal}; return transaction; } void push_proposal(database_fixture& fixture, const account_object& fee_payer, const std::vector& operations) { proposal_create_operation operation_proposal; operation_proposal.fee_paying_account = fee_payer.id; for (auto& operation: operations) { operation_proposal.proposed_ops.push_back(op_wrapper(operation)); } operation_proposal.expiration_time = fixture.db.head_block_time() + fc::days(1); signed_transaction transaction; transaction.operations.push_back(operation_proposal); set_expiration( fixture.db, transaction ); fixture.sign( transaction, fixture.init_account_priv_key ); PUSH_TX( fixture.db, transaction ); } } BOOST_FIXTURE_TEST_SUITE( check_tansaction_for_duplicated_operations, database_fixture ) BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_twice ) { try { ACTORS((alice)) 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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_without_duplication ) { try { ACTORS((alice)) auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_for_the_same_operation_with_different_assets ) { try { ACTORS((alice)) 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(501))}); BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_fails_for_duplication_in_transaction_with_several_operations ) { try { ACTORS((alice)) 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(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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_with_several_operations_and_transaction_with_several_operations ) { try { ACTORS((alice)) create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(499)), 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(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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_with_several_operations ) { try { ACTORS((alice)) create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(499)), 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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_for_different_operations_types ) { try { ACTORS((alice)) create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); auto trx = make_signed_transaction_with_proposed_operation(*this, {make_committee_member_create_operation(asset(1000), account_id_type(), "test url")}); BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_fails_for_same_member_create_operations ) { try { 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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_for_different_member_create_operations ) { try { 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(1001), account_id_type(), "test url")}); BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_failes_for_several_operations_of_mixed_type ) { try { ACTORS((alice)) create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500)), make_committee_member_create_operation(asset(1000), account_id_type(), "test url")}); create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)), //duplicate make_committee_member_create_operation(asset(1001), account_id_type(), "test url")}); 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); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_failes_for_duplicates_in_pending_transactions_list ) { try { ACTORS((alice)) fc::ecc::private_key committee_key = init_account_priv_key; const account_object& moneyman = create_account("moneyman", init_account_pub_key); const asset_object& core = asset_id_type()(db); transfer(account_id_type()(db), moneyman, core.amount(1000000)); auto duplicate = make_transfer_operation(alice.id, moneyman.get_id(), asset(100)); push_proposal(*this, moneyman, {duplicate}); auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate}); BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_for_no_duplicates_in_pending_transactions_list ) { try { ACTORS((alice)) fc::ecc::private_key committee_key = init_account_priv_key; const account_object& moneyman = create_account("moneyman", init_account_pub_key); const asset_object& core = asset_id_type()(db); transfer(account_id_type()(db), moneyman, core.amount(1000000)); push_proposal(*this, moneyman, {make_transfer_operation(alice.id, moneyman.get_id(), asset(100))}); auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(alice.id, moneyman.get_id(), asset(101))}); BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_fails_for_several_transactions_with_duplicates_in_pending_list ) { try { ACTORS((alice)) fc::ecc::private_key committee_key = init_account_priv_key; const account_object& moneyman = create_account("moneyman", init_account_pub_key); const asset_object& core = asset_id_type()(db); transfer(account_id_type()(db), moneyman, core.amount(1000000)); auto duplicate = make_transfer_operation(alice.id, moneyman.get_id(), asset(100)); push_proposal(*this, moneyman, {make_transfer_operation(alice.id, moneyman.get_id(), asset(101)), duplicate}); auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate, make_transfer_operation(alice.id, moneyman.get_id(), asset(102))}); BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_or_group ) { generate_blocks( HARDFORK_1000_TIME + fc::seconds(300) ); try { const sport_id_type sport_id = create_sport( {{"SN","SPORT_NAME"}} ).id; const event_group_id_type event_group_id = create_event_group( {{"EG", "EVENT_GROUP"}}, sport_id ).id; const betting_market_rules_id_type betting_market_rules_id = create_betting_market_rules( {{"EN", "Rules"}}, {{"EN", "Some rules"}} ).id; event_create_operation evcop1; evcop1.event_group_id = event_group_id; evcop1.name = {{"NO", "NAME_ONE"}}; evcop1.season = {{"NO", "NAME_ONE"}}; event_create_operation evcop2; evcop2.event_group_id = event_group_id; evcop2.name = {{"NT", "NAME_TWO"}}; evcop2.season = {{"NT", "NAME_TWO"}}; betting_market_group_create_operation bmgcop; bmgcop.description = {{"NN", "NO_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" ) ); proposal_create_operation pcop1 = proposal_create_operation::committee_proposal( db.get_global_properties().parameters, db.head_block_time() ); pcop1.review_period_seconds.reset(); proposal_create_operation pcop2 = pcop1; trx.clear(); pcop1.proposed_ops.emplace_back( evcop1 ); pcop1.proposed_ops.emplace_back( bmgcop ); pcop1.proposed_ops.emplace_back( bmcop ); pcop2.proposed_ops.emplace_back( evcop2 ); pcop2.proposed_ops.emplace_back( bmgcop ); pcop2.proposed_ops.emplace_back( bmcop ); create_proposal(*this, { pcop1, pcop2 }); auto trx = make_signed_transaction_with_proposed_operation(*this, { pcop1, pcop2 }); BOOST_CHECK_NO_THROW( db.check_tansaction_for_duplicated_operations(trx) ); } catch( const fc::exception& e ) { edump((e.to_detail_string())); throw; } } BOOST_AUTO_TEST_SUITE_END() BOOST_FIXTURE_TEST_SUITE(network_broadcast_api_tests, database_fixture) BOOST_AUTO_TEST_CASE( broadcast_transaction_with_callback_test ) { try { uint32_t called = 0; auto callback = [&]( const variant& v ) { ++called; }; fc::ecc::private_key cid_key = fc::ecc::private_key::regenerate( fc::digest("key") ); const account_id_type cid_id = create_account( "cid", cid_key.get_public_key() ).id; fund( cid_id(db) ); auto nb_api = std::make_shared< graphene::app::network_broadcast_api >( app ); set_expiration( db, trx ); transfer_operation trans; trans.from = cid_id; trans.to = account_id_type(); trans.amount = asset(1); trx.operations.push_back( trans ); sign( trx, cid_key ); nb_api->broadcast_transaction_with_callback( callback, trx ); trx.operations.clear(); trx.signatures.clear(); generate_block(); fc::usleep(fc::milliseconds(200)); // sleep a while to execute callback in another thread BOOST_CHECK_EQUAL( called, 1 ); } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END()