From ee8429938cc1047f229aebf3057ab7382cc518e2 Mon Sep 17 00:00:00 2001 From: dimfred Date: Mon, 28 Jan 2019 11:51:26 +0100 Subject: [PATCH 1/5] moved check_trx_for_duplicate_operation and digest_accumulator to database api --- libraries/app/database_api.cpp | 68 +++++++++++++++++++ .../app/include/graphene/app/database_api.hpp | 7 ++ libraries/chain/db_block.cpp | 61 ----------------- .../chain/include/graphene/chain/database.hpp | 2 - 4 files changed, 75 insertions(+), 63 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d3af2f29..7a485091 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -45,6 +45,42 @@ typedef std::map< std::pair, std::vector > market_queue_type; + +namespace { + + struct proposed_operations_digest_accumulator + { + typedef void result_type; + + void operator()(const graphene::chain::proposal_create_operation& proposal) + { + for (auto& operation: proposal.proposed_ops) + { + proposed_operations_digests.push_back(fc::digest(operation.op)); + } + } + + //empty template method is needed for all other operation types + //we can ignore them, we are interested in only proposal_create_operation + template + void operator()(const T&) + {} + + std::vector proposed_operations_digests; + }; + + std::vector gather_proposed_operations_digests(const graphene::chain::transaction& trx) + { + proposed_operations_digest_accumulator digest_accumulator; + for (auto& operation: trx.operations) + { + operation.visit(digest_accumulator); + } + + return digest_accumulator.proposed_operations_digests; + } +} + namespace graphene { namespace app { class database_api_impl; @@ -70,6 +106,7 @@ class database_api_impl : public std::enable_shared_from_this map> get_block_header_batch(const vector block_nums)const; optional get_block(uint32_t block_num)const; processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const; + void check_transaction_for_duplicated_operations(const signed_transaction& trx); // Globals chain_property_object get_chain_properties()const; @@ -429,6 +466,37 @@ processed_transaction database_api_impl::get_transaction(uint32_t block_num, uin return opt_block->transactions[trx_num]; } +void database_api::check_transaction_for_duplicated_operations(const signed_transaction& trx) +{ + my->check_transaction_for_duplicated_operations(trx); +} + +void database_api_impl::check_transaction_for_duplicated_operations(const signed_transaction& trx) +{ + const auto& proposal_index = get_index(); + std::set existed_operations_digests; + + proposal_index.inspect_all_objects( [&](const object& obj){ + const proposal_object& proposal = static_cast(obj); + for (auto& operation: proposal.proposed_transaction.operations) + { + existed_operations_digests.insert(fc::digest(operation)); + } + }); + + for (auto& pending_transaction: _pending_tx) + { + auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction); + existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end()); + } + + auto proposed_operations_digests = gather_proposed_operations_digests(trx); + for (auto& digest: proposed_operations_digests) + { + FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for approval."); + } +} + ////////////////////////////////////////////////////////////////////// // // // Globals // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 7b0943e4..2b70d965 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -192,6 +192,12 @@ class database_api */ optional get_recent_transaction_by_id( const transaction_id_type& id )const; + /** + * TODO + * + */ + void check_transaction_for_duplicated_operations(const signed_transaction& trx); + ///////////// // Globals // ///////////// @@ -645,6 +651,7 @@ class database_api */ vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; + private: std::shared_ptr< database_api_impl > my; }; diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 66126dbf..0203911c 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -40,41 +40,6 @@ #include -namespace { - - struct proposed_operations_digest_accumulator - { - typedef void result_type; - - void operator()(const graphene::chain::proposal_create_operation& proposal) - { - for (auto& operation: proposal.proposed_ops) - { - proposed_operations_digests.push_back(fc::digest(operation.op)); - } - } - - //empty template method is needed for all other operation types - //we can ignore them, we are interested in only proposal_create_operation - template - void operator()(const T&) - {} - - std::vector proposed_operations_digests; - }; - - std::vector gather_proposed_operations_digests(const graphene::chain::transaction& trx) - { - proposed_operations_digest_accumulator digest_accumulator; - for (auto& operation: trx.operations) - { - operation.visit(digest_accumulator); - } - - return digest_accumulator.proposed_operations_digests; - } -} - namespace graphene { namespace chain { bool database::is_known_block( const block_id_type& id )const @@ -140,32 +105,6 @@ std::vector database::get_block_ids_on_fork(block_id_type head_of result.emplace_back(branches.first.back()->previous_id()); return result; } - -void database::check_tansaction_for_duplicated_operations(const signed_transaction& trx) -{ - const auto& proposal_index = get_index(); - std::set existed_operations_digests; - - proposal_index.inspect_all_objects( [&](const object& obj){ - const proposal_object& proposal = static_cast(obj); - for (auto& operation: proposal.proposed_transaction.operations) - { - existed_operations_digests.insert(fc::digest(operation)); - } - }); - - for (auto& pending_transaction: _pending_tx) - { - auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction); - existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end()); - } - - auto proposed_operations_digests = gather_proposed_operations_digests(trx); - for (auto& digest: proposed_operations_digests) - { - FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for approval."); - } -} /** * Push block "may fail" in which case every partial change is unwound. After diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index af50a94b..02fe64f6 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -136,8 +136,6 @@ namespace graphene { namespace chain { void add_checkpoints( const flat_map& checkpts ); const flat_map get_checkpoints()const { return _checkpoints; } bool before_last_checkpoint()const; - - void check_tansaction_for_duplicated_operations(const signed_transaction& trx); bool push_block( const signed_block& b, uint32_t skip = skip_nothing ); processed_transaction push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing ); From 2922366e27a06e1871c674b7baaee58fed5f495a Mon Sep 17 00:00:00 2001 From: dimfred Date: Mon, 28 Jan 2019 15:05:20 +0100 Subject: [PATCH 2/5] changed check_transaction to check only for proposals associated with GRAPHENE_WITNESS_ACC --- libraries/app/database_api.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 7a485091..9047c793 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -473,27 +473,26 @@ void database_api::check_transaction_for_duplicated_operations(const signed_tran void database_api_impl::check_transaction_for_duplicated_operations(const signed_transaction& trx) { - const auto& proposal_index = get_index(); + const auto& idx = _db.get_index_type(); + const auto& pidx = dynamic_cast&>(idx); + const auto& raidx = pidx.get_secondary_index(); + + auto& p_set = raidx._account_to_proposals.find( GRAPHENE_WITNESS_ACCOUNT )->second; + std::set existed_operations_digests; - proposal_index.inspect_all_objects( [&](const object& obj){ - const proposal_object& proposal = static_cast(obj); - for (auto& operation: proposal.proposed_transaction.operations) - { - existed_operations_digests.insert(fc::digest(operation)); - } - }); - - for (auto& pending_transaction: _pending_tx) + for( auto p_itr = p_set.begin(); p_itr != p_set.end(); ++p_itr ) { - auto proposed_operations_digests = gather_proposed_operations_digests(pending_transaction); - existed_operations_digests.insert(proposed_operations_digests.begin(), proposed_operations_digests.end()); + for( auto& operation : (*p_itr)(_db).proposed_transaction.operations ) + { + exited_operations_digests.insert( fc::digest(operation) ); + } } auto proposed_operations_digests = gather_proposed_operations_digests(trx); - for (auto& digest: proposed_operations_digests) + for (auto& digest : proposed_operations_digests) { - FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for approval."); + FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for apsproval."); } } From c86237cd86e48861057ab9e1bc28c24d181928ac Mon Sep 17 00:00:00 2001 From: dimfred Date: Mon, 28 Jan 2019 15:13:15 +0100 Subject: [PATCH 3/5] changed api.cpp accordingly --- libraries/app/api.cpp | 4 ++-- libraries/app/database_api.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index d46eab07..209416a6 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -169,14 +169,14 @@ namespace graphene { namespace app { void network_broadcast_api::broadcast_transaction(const signed_transaction& trx) { trx.validate(); - _app.chain_database()->check_tansaction_for_duplicated_operations(trx); + database_api( *(_app.chain_database() ) ).check_transaction_for_duplicated_operations(trx); _app.chain_database()->push_transaction(trx); _app.p2p_node()->broadcast_transaction(trx); } fc::variant network_broadcast_api::broadcast_transaction_synchronous(const signed_transaction& trx) { - _app.chain_database()->check_tansaction_for_duplicated_operations(trx); + database_api( *(_app.chain_database() ) ).check_transaction_for_duplicated_operations(trx); fc::promise::ptr prom( new fc::promise() ); broadcast_transaction_with_callback( [=]( const fc::variant& v ){ diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 9047c793..748c5831 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -485,7 +486,7 @@ void database_api_impl::check_transaction_for_duplicated_operations(const signed { for( auto& operation : (*p_itr)(_db).proposed_transaction.operations ) { - exited_operations_digests.insert( fc::digest(operation) ); + existed_operations_digests.insert( fc::digest(operation) ); } } From 75e339e42f622b55b52bdb15b7fc7b322cd48d8f Mon Sep 17 00:00:00 2001 From: dimfred Date: Fri, 1 Feb 2019 19:17:34 +0100 Subject: [PATCH 4/5] Fixed network_broadcast_tests, added cases --- tests/tests/network_broadcast_api_tests.cpp | 200 ++++++++++++++------ 1 file changed, 142 insertions(+), 58 deletions(-) diff --git a/tests/tests/network_broadcast_api_tests.cpp b/tests/tests/network_broadcast_api_tests.cpp index 1c061fb3..427508ce 100644 --- a/tests/tests/network_broadcast_api_tests.cpp +++ b/tests/tests/network_broadcast_api_tests.cpp @@ -5,7 +5,9 @@ #include #include #include +#include #include +#include #include "../common/database_fixture.hpp" @@ -24,6 +26,27 @@ namespace return transfer; } + sport_create_operation make_sport_create_operation(std::string s1, std::string s2) + { + sport_create_operation op; + op.name = {{ s1, s2 }}; + return op; + } + + betting_market_group_create_operation make_betting_market_group_create(string s1, string s2) + { + betting_market_group_create_operation op; + op.description = {{ s1, s2 }}; + return op; + } + + betting_market_create_operation make_betting_market_operation(string s1, string s2) + { + betting_market_create_operation op; + op.description = {{ s1, s2 }}; + return op; + } + 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; @@ -44,6 +67,7 @@ namespace fixture.db.create([&](proposal_object& proposal) { proposal.proposed_transaction = transaction; + proposal.required_active_approvals = { GRAPHENE_WITNESS_ACCOUNT }; }); } @@ -84,18 +108,16 @@ namespace } } -BOOST_FIXTURE_TEST_SUITE( check_tansaction_for_duplicated_operations, database_fixture ) +BOOST_FIXTURE_TEST_SUITE( check_transaction_for_duplicated_operations, database_fixture ) -BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_twice ) +BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_for_witness_twice ) { try { - ACTORS((alice)) + create_proposal(*this, {make_sport_create_operation("SPORT1", "S1")}); - 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))}); - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT1", "S1")} ); + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -108,10 +130,8 @@ 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)); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT1", "S1")}); + BOOST_CHECK_NO_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { @@ -120,16 +140,14 @@ BOOST_AUTO_TEST_CASE( check_passes_without_duplication ) } } -BOOST_AUTO_TEST_CASE( check_passes_for_the_same_operation_with_different_assets ) +BOOST_AUTO_TEST_CASE( check_passes_for_the_same_operation_with_different_names ) { try { - ACTORS((alice)) + create_proposal(*this, {make_sport_create_operation("SPORT1", "S1")}); - 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)); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT2", "S2")}); + BOOST_CHECK_NO_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { @@ -142,13 +160,11 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplication_in_transaction_with_several_op { try { - ACTORS((alice)) + create_proposal(*this, {make_sport_create_operation("SPORT1", "S1")}); - 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 - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT2", "S2"), + make_sport_create_operation("SPORT1", "S1") }); //duplicated one + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -161,14 +177,12 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w { try { - ACTORS((alice)) + create_proposal(*this, {make_sport_create_operation("SPORT1", "S1"), + make_sport_create_operation("SPORT2", "S2") }); //duplicated one - 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 - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT3", "S3"), + make_sport_create_operation("SPORT2", "S2")}); //duplicated one + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -181,13 +195,11 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w { try { - ACTORS((alice)) + create_proposal(*this, {make_sport_create_operation("SPORT1", "S1"), + make_sport_create_operation("SPORT2", "S2")}); //duplicated one - 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 - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + auto trx = make_signed_transaction_with_proposed_operation(*this, {make_sport_create_operation("SPORT2", "S2")}); //duplicated one + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -200,12 +212,12 @@ BOOST_AUTO_TEST_CASE( check_passes_for_different_operations_types ) { try { - ACTORS((alice)) + ACTOR( 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)); + BOOST_CHECK_NO_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { @@ -221,7 +233,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")}); - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -237,7 +249,7 @@ BOOST_AUTO_TEST_CASE( check_passes_for_different_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(1001), account_id_type(), "test url")}); - BOOST_CHECK_NO_THROW(db.check_tansaction_for_duplicated_operations(trx)); + BOOST_CHECK_NO_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { @@ -261,7 +273,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")}); - BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception); + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -274,20 +286,15 @@ BOOST_AUTO_TEST_CASE( check_failes_for_duplicates_in_pending_transactions_list ) { try { - ACTORS((alice)) + ACTOR( alice ); - fc::ecc::private_key committee_key = init_account_priv_key; + auto duplicate = make_sport_create_operation("SPORT1", "S1"); - const account_object& moneyman = create_account("moneyman", init_account_pub_key); - const asset_object& core = asset_id_type()(db); + push_proposal( *this, GRAPHENE_WITNESS_ACCOUNT(db), {duplicate} ); - transfer(account_id_type()(db), moneyman, core.amount(1000000)); + auto trx = make_signed_transaction_with_proposed_operation( *this, {duplicate} ); - 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); + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -312,7 +319,7 @@ BOOST_AUTO_TEST_CASE( check_passes_for_no_duplicates_in_pending_transactions_lis 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)); + BOOST_CHECK_NO_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx)); } catch( const fc::exception& e ) { @@ -334,13 +341,13 @@ BOOST_AUTO_TEST_CASE( check_fails_for_several_transactions_with_duplicates_in_pe 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 duplicate = make_sport_create_operation("SPORT1", "S1"); + push_proposal(*this, moneyman, {make_sport_create_operation("SPORT2", "S2"), 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); + auto trx = make_signed_transaction_with_proposed_operation(*this, + {duplicate, make_sport_create_operation("SPORT3", "S3")} ); + + BOOST_CHECK_THROW(graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx), fc::exception); } catch( const fc::exception& e ) { @@ -349,4 +356,81 @@ BOOST_AUTO_TEST_CASE( check_fails_for_several_transactions_with_duplicates_in_pe } } +BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_group_create ) +{ + try + { + auto duplicate = make_betting_market_group_create( "BMGROUP1", "BMG1" ); + + create_proposal(*this, {duplicate} ); + + auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate} ); + + BOOST_CHECK_NO_THROW( graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx) ); + } + catch( const fc::exception &e ) + { + edump( ( e.to_detail_string() ) ); + throw; + } +} + +BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_create ) +{ + try + { + auto duplicate = make_betting_market_operation( "BMARKET1", "BM1" ); + + create_proposal( *this, {duplicate} ); + + auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate} ); + + BOOST_CHECK_NO_THROW( graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx) ); + } + catch( const fc::exception &e ) + { + edump( ( e.to_detail_string() ) ); + throw; + } +} + +BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_and_betting_market_group_create ) +{ + try + { + auto duplicate_market = make_betting_market_operation( "BMARKET1", "BM1" ); + auto duplicate_group = make_betting_market_group_create( "BMGROUP1", "BMG1" ); + + create_proposal( *this, {duplicate_market, duplicate_group} ); + + auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate_market, duplicate_group} ); + + BOOST_CHECK_NO_THROW( graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx) ); + } + catch( const fc::exception &e ) + { + edump( ( e.to_detail_string() ) ); + throw; + } +} + +BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_in_one_operation ) +{ + try + { + auto duplicate = make_betting_market_operation( "BMARKET1", "BM1" ); + + create_proposal( *this, {duplicate, duplicate} ); + + auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate, duplicate} ); + + BOOST_CHECK_NO_THROW( graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx) ); + } + catch( const fc::exception &e ) + { + edump( ( e.to_detail_string() ) ); + throw; + } +} + BOOST_AUTO_TEST_SUITE_END() From 87bf4be89bb5c6c1f06bd11e0034cc5e2d23de75 Mon Sep 17 00:00:00 2001 From: dimfred Date: Wed, 6 Feb 2019 13:49:31 +0100 Subject: [PATCH 5/5] digest_accumulator picks out bm_create and bmg_create and reworked duplicate check --- libraries/app/database_api.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 748c5831..4d1b60ea 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -57,7 +57,9 @@ namespace { { for (auto& operation: proposal.proposed_ops) { - proposed_operations_digests.push_back(fc::digest(operation.op)); + if( operation.op.which() != graphene::chain::operation::tag::value + && operation.op.which() != graphene::chain::operation::tag::value ) + proposed_operations_digests.push_back(fc::digest(operation.op)); } } @@ -477,23 +479,26 @@ void database_api_impl::check_transaction_for_duplicated_operations(const signed const auto& idx = _db.get_index_type(); const auto& pidx = dynamic_cast&>(idx); const auto& raidx = pidx.get_secondary_index(); - - auto& p_set = raidx._account_to_proposals.find( GRAPHENE_WITNESS_ACCOUNT )->second; - std::set existed_operations_digests; - - for( auto p_itr = p_set.begin(); p_itr != p_set.end(); ++p_itr ) + auto acc_itr = raidx._account_to_proposals.find( GRAPHENE_WITNESS_ACCOUNT ); + if( acc_itr != raidx._account_to_proposals.end() ) { - for( auto& operation : (*p_itr)(_db).proposed_transaction.operations ) + auto& p_set = acc_itr->second; + + std::set existed_operations_digests; + for( auto p_itr = p_set.begin(); p_itr != p_set.end(); ++p_itr ) { - existed_operations_digests.insert( fc::digest(operation) ); + for( auto& operation : (*p_itr)(_db).proposed_transaction.operations ) + { + existed_operations_digests.insert( fc::digest(operation) ); + } + } + + auto proposed_operations_digests = gather_proposed_operations_digests(trx); + for (auto& digest : proposed_operations_digests) + { + FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for apsproval."); } - } - - auto proposed_operations_digests = gather_proposed_operations_digests(trx); - for (auto& digest : proposed_operations_digests) - { - FC_ASSERT(existed_operations_digests.count(digest) == 0, "Proposed operation is already pending for apsproval."); } }