Merge pull request #14 from peerplays-network/feature/duplicate-operation-check-hardfork
Feature/duplicate operation check hardfork
This commit is contained in:
commit
89361e58af
5 changed files with 212 additions and 108 deletions
|
|
@ -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<fc::variant>::ptr prom( new fc::promise<fc::variant>() );
|
||||
broadcast_transaction_with_callback( [=]( const fc::variant& v ){
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <fc/smart_ref_impl.hpp>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/digest.hpp>
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
|
@ -45,6 +46,44 @@
|
|||
|
||||
typedef std::map< std::pair<graphene::chain::asset_id_type, graphene::chain::asset_id_type>, std::vector<fc::variant> > 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)
|
||||
{
|
||||
if( operation.op.which() != graphene::chain::operation::tag<graphene::chain::betting_market_group_create_operation>::value
|
||||
&& operation.op.which() != graphene::chain::operation::tag<graphene::chain::betting_market_create_operation>::value )
|
||||
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<class T>
|
||||
void operator()(const T&)
|
||||
{}
|
||||
|
||||
std::vector<fc::sha256> proposed_operations_digests;
|
||||
};
|
||||
|
||||
std::vector<fc::sha256> 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 +109,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
|
|||
map<uint32_t, optional<block_header>> get_block_header_batch(const vector<uint32_t> block_nums)const;
|
||||
optional<signed_block> 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 +469,39 @@ 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& idx = _db.get_index_type<proposal_index>();
|
||||
const auto& pidx = dynamic_cast<const primary_index<proposal_index>&>(idx);
|
||||
const auto& raidx = pidx.get_secondary_index<graphene::chain::required_approval_index>();
|
||||
|
||||
auto acc_itr = raidx._account_to_proposals.find( GRAPHENE_WITNESS_ACCOUNT );
|
||||
if( acc_itr != raidx._account_to_proposals.end() )
|
||||
{
|
||||
auto& p_set = acc_itr->second;
|
||||
|
||||
std::set<fc::sha256> existed_operations_digests;
|
||||
for( auto p_itr = p_set.begin(); p_itr != p_set.end(); ++p_itr )
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Globals //
|
||||
|
|
|
|||
|
|
@ -192,6 +192,12 @@ class database_api
|
|||
*/
|
||||
optional<signed_transaction> 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<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr< database_api_impl > my;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -136,8 +136,6 @@ namespace graphene { namespace chain {
|
|||
void add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts );
|
||||
const flat_map<uint32_t,block_id_type> 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 );
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
#include <graphene/chain/proposal_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/protocol/committee_member.hpp>
|
||||
#include <graphene/chain/protocol/sport.hpp>
|
||||
#include <fc/crypto/digest.hpp>
|
||||
#include <graphene/app/database_api.hpp>
|
||||
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
|
|
@ -28,6 +30,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;
|
||||
|
|
@ -48,6 +71,7 @@ namespace
|
|||
fixture.db.create<proposal_object>([&](proposal_object& proposal)
|
||||
{
|
||||
proposal.proposed_transaction = transaction;
|
||||
proposal.required_active_approvals = { GRAPHENE_WITNESS_ACCOUNT };
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -88,18 +112,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 )
|
||||
{
|
||||
|
|
@ -112,10 +134,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 )
|
||||
{
|
||||
|
|
@ -124,16 +144,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 )
|
||||
{
|
||||
|
|
@ -146,13 +164,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 )
|
||||
{
|
||||
|
|
@ -165,14 +181,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 )
|
||||
{
|
||||
|
|
@ -185,13 +199,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 )
|
||||
{
|
||||
|
|
@ -204,12 +216,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 )
|
||||
{
|
||||
|
|
@ -225,7 +237,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 )
|
||||
{
|
||||
|
|
@ -241,7 +253,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 )
|
||||
{
|
||||
|
|
@ -265,7 +277,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 )
|
||||
{
|
||||
|
|
@ -278,20 +290,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 )
|
||||
{
|
||||
|
|
@ -316,7 +323,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 )
|
||||
{
|
||||
|
|
@ -338,13 +345,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 )
|
||||
{
|
||||
|
|
@ -353,61 +360,80 @@ BOOST_AUTO_TEST_CASE( check_fails_for_several_transactions_with_duplicates_in_pe
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_or_group )
|
||||
BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_group_create )
|
||||
{
|
||||
generate_blocks( HARDFORK_1000_TIME + fc::seconds(300) );
|
||||
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
|
||||
{
|
||||
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"}};
|
||||
auto duplicate = make_betting_market_operation( "BMARKET1", "BM1" );
|
||||
|
||||
event_create_operation evcop2;
|
||||
evcop2.event_group_id = event_group_id;
|
||||
evcop2.name = {{"NT", "NAME_TWO"}};
|
||||
evcop2.season = {{"NT", "NAME_TWO"}};
|
||||
create_proposal( *this, {duplicate} );
|
||||
|
||||
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();
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {duplicate} );
|
||||
|
||||
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;
|
||||
|
||||
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) );
|
||||
BOOST_CHECK_NO_THROW( graphene::app::database_api(db).check_transaction_for_duplicated_operations(trx) );
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
catch( const fc::exception &e )
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue