2018-07-04 16:49:05 +00:00
# include <boost/test/unit_test.hpp>
2018-07-04 16:31:32 +00:00
2018-12-12 10:36:23 +00:00
# include <graphene/chain/hardfork.hpp>
# include <graphene/chain/sport_object.hpp>
# include <graphene/chain/event_group_object.hpp>
# include <graphene/chain/betting_market_object.hpp>
2018-07-04 16:31:32 +00:00
# include <graphene/chain/exceptions.hpp>
2018-07-04 16:49:05 +00:00
# include <graphene/chain/protocol/proposal.hpp>
# include <graphene/chain/proposal_object.hpp>
2018-07-06 12:29:15 +00:00
# include <graphene/chain/witness_object.hpp>
# include <graphene/chain/protocol/committee_member.hpp>
2018-03-25 21:40:32 +00:00
# include <graphene/app/api.hpp>
2018-07-04 16:31:32 +00:00
# include <fc/crypto/digest.hpp>
# 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 ;
2018-10-12 05:53:01 +00:00
2018-07-04 16:31:32 +00:00
return transfer ;
}
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
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 ;
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
return member_create_operation ;
}
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
void create_proposal ( database_fixture & fixture , const std : : vector < operation > & operations )
2018-07-04 16:31:32 +00:00
{
signed_transaction transaction ;
set_expiration ( fixture . db , transaction ) ;
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
transaction . operations = operations ;
2018-10-12 05:53:01 +00:00
2018-07-04 16:31:32 +00:00
fixture . db . create < proposal_object > ( [ & ] ( proposal_object & proposal )
{
proposal . proposed_transaction = transaction ;
} ) ;
}
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
signed_transaction make_signed_transaction_with_proposed_operation ( database_fixture & fixture , const std : : vector < operation > & operations )
2018-07-04 16:31:32 +00:00
{
2018-07-05 09:58:59 +00:00
proposal_create_operation operation_proposal ;
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
for ( auto & operation : operations )
{
2018-07-05 13:16:16 +00:00
operation_proposal . proposed_ops . push_back ( op_wrapper ( operation ) ) ;
2018-07-05 10:58:36 +00:00
}
2018-10-12 05:53:01 +00:00
2018-07-05 09:58:59 +00:00
signed_transaction transaction ;
2018-07-05 10:58:36 +00:00
set_expiration ( fixture . db , transaction ) ;
2018-07-05 09:58:59 +00:00
transaction . operations = { operation_proposal } ;
2018-10-12 05:53:01 +00:00
2018-07-05 09:58:59 +00:00
return transaction ;
2018-07-04 16:31:32 +00:00
}
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
void push_proposal ( database_fixture & fixture , const account_object & fee_payer , const std : : vector < operation > & operations )
{
proposal_create_operation operation_proposal ;
operation_proposal . fee_paying_account = fee_payer . id ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
for ( auto & operation : operations )
{
operation_proposal . proposed_ops . push_back ( op_wrapper ( operation ) ) ;
}
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
operation_proposal . expiration_time = fixture . db . head_block_time ( ) + fc : : days ( 1 ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
signed_transaction transaction ;
transaction . operations . push_back ( operation_proposal ) ;
set_expiration ( fixture . db , transaction ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
fixture . sign ( transaction , fixture . init_account_priv_key ) ;
PUSH_TX ( fixture . db , transaction ) ;
}
2018-07-04 16:31:32 +00:00
}
2018-07-05 10:58:36 +00:00
BOOST_FIXTURE_TEST_SUITE ( check_tansaction_for_duplicated_operations , database_fixture )
2018-07-04 16:31:32 +00:00
BOOST_AUTO_TEST_CASE ( test_exception_throwing_for_the_same_operation_proposed_twice )
{
try
{
2018-07-04 16:49:05 +00:00
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
create_proposal ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
auto trx = make_signed_transaction_with_proposed_operation ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2019-06-14 17:26:42 +00:00
//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
2019-08-30 10:06:41 +00:00
BOOST_WARN_THROW ( db . check_tansaction_for_duplicated_operations ( trx ) , fc : : exception ) ;
2018-07-04 16:31:32 +00:00
}
catch ( const fc : : exception & e )
{
edump ( ( e . to_detail_string ( ) ) ) ;
throw ;
}
}
2018-07-05 10:58:36 +00:00
BOOST_AUTO_TEST_CASE ( check_passes_without_duplication )
2018-07-04 16:49:05 +00:00
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
auto trx = make_signed_transaction_with_proposed_operation ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2018-07-05 09:58:59 +00:00
BOOST_CHECK_NO_THROW ( db . check_tansaction_for_duplicated_operations ( trx ) ) ;
2018-07-04 16:49:05 +00:00
}
catch ( const fc : : exception & e )
{
edump ( ( e . to_detail_string ( ) ) ) ;
throw ;
}
}
2018-07-05 10:58:36 +00:00
BOOST_AUTO_TEST_CASE ( check_passes_for_the_same_operation_with_different_assets )
2018-07-04 16:49:05 +00:00
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
create_proposal ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
auto trx = make_signed_transaction_with_proposed_operation ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 501 ) ) } ) ;
2018-07-05 09:58:59 +00:00
BOOST_CHECK_NO_THROW ( db . check_tansaction_for_duplicated_operations ( trx ) ) ;
2018-07-04 16:49:05 +00:00
}
catch ( const fc : : exception & e )
{
edump ( ( e . to_detail_string ( ) ) ) ;
throw ;
}
}
2018-07-05 10:58:36 +00:00
BOOST_AUTO_TEST_CASE ( check_fails_for_duplication_in_transaction_with_several_operations )
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
create_proposal ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
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
2019-06-14 17:26:42 +00:00
//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 ) ;
2018-07-05 10:58:36 +00:00
}
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 ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
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
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
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
2019-06-14 17:26:42 +00:00
//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 ) ;
2018-07-05 10:58:36 +00:00
}
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 ) )
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
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
2018-10-12 05:53:01 +00:00
2018-07-05 10:58:36 +00:00
auto trx = make_signed_transaction_with_proposed_operation ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ; //duplicated one
2019-06-14 17:26:42 +00:00
//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
2019-08-30 10:06:41 +00:00
BOOST_WARN_THROW ( db . check_tansaction_for_duplicated_operations ( trx ) , fc : : exception ) ;
2018-07-05 10:58:36 +00:00
}
catch ( const fc : : exception & e )
{
edump ( ( e . to_detail_string ( ) ) ) ;
throw ;
}
}
2018-07-06 12:29:15 +00:00
BOOST_AUTO_TEST_CASE ( check_passes_for_different_operations_types )
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
create_proposal ( * this , { make_transfer_operation ( account_id_type ( ) , alice_id , asset ( 500 ) ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
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 " ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
auto trx = make_signed_transaction_with_proposed_operation ( * this , { make_committee_member_create_operation ( asset ( 1000 ) , account_id_type ( ) , " test url " ) } ) ;
2019-06-14 17:26:42 +00:00
//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
2019-08-30 10:06:41 +00:00
BOOST_WARN_THROW ( db . check_tansaction_for_duplicated_operations ( trx ) , fc : : exception ) ;
2018-07-06 12:29:15 +00:00
}
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 " ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-06 12:29:15 +00:00
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 ;
}
}
2018-07-06 13:40:05 +00:00
BOOST_AUTO_TEST_CASE ( check_failes_for_several_operations_of_mixed_type )
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-06 13:40:05 +00:00
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 " ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-06 13:40:05 +00:00
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 " ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-06 13:40:05 +00:00
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 " ) } ) ;
2018-10-12 05:53:01 +00:00
2019-06-14 17:26:42 +00:00
//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 ) ;
2018-07-06 13:40:05 +00:00
}
catch ( const fc : : exception & e )
{
edump ( ( e . to_detail_string ( ) ) ) ;
throw ;
}
}
2018-07-12 14:18:55 +00:00
BOOST_AUTO_TEST_CASE ( check_failes_for_duplicates_in_pending_transactions_list )
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
fc : : ecc : : private_key committee_key = init_account_priv_key ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
const account_object & moneyman = create_account ( " moneyman " , init_account_pub_key ) ;
const asset_object & core = asset_id_type ( ) ( db ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
transfer ( account_id_type ( ) ( db ) , moneyman , core . amount ( 1000000 ) ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
auto duplicate = make_transfer_operation ( alice . id , moneyman . get_id ( ) , asset ( 100 ) ) ;
push_proposal ( * this , moneyman , { duplicate } ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
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 ) )
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
fc : : ecc : : private_key committee_key = init_account_priv_key ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
const account_object & moneyman = create_account ( " moneyman " , init_account_pub_key ) ;
const asset_object & core = asset_id_type ( ) ( db ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
transfer ( account_id_type ( ) ( db ) , moneyman , core . amount ( 1000000 ) ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
push_proposal ( * this , moneyman , { make_transfer_operation ( alice . id , moneyman . get_id ( ) , asset ( 100 ) ) } ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
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 ;
}
}
2018-10-12 05:53:01 +00:00
BOOST_AUTO_TEST_CASE ( check_fails_for_several_transactions_with_duplicates_in_pending_list )
2018-07-12 14:18:55 +00:00
{
try
{
ACTORS ( ( alice ) )
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
fc : : ecc : : private_key committee_key = init_account_priv_key ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
const account_object & moneyman = create_account ( " moneyman " , init_account_pub_key ) ;
const asset_object & core = asset_id_type ( ) ( db ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
transfer ( account_id_type ( ) ( db ) , moneyman , core . amount ( 1000000 ) ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
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 } ) ;
2018-10-12 05:53:01 +00:00
2018-07-12 14:18:55 +00:00
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 ;
}
}
2018-12-12 10:36:23 +00:00
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 ;
2019-08-30 10:06:41 +00:00
const betting_market_rules_id_type betting_market_rules_id =
2018-12-12 10:36:23 +00:00
create_betting_market_rules ( { { " EN " , " Rules " } } , { { " EN " , " Some rules " } } ) . id ;
2019-08-30 10:06:41 +00:00
2018-12-12 10:36:23 +00:00
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 ;
2019-08-30 10:06:41 +00:00
bmgcop . asset_id = asset_id_type ( ) ;
2018-12-12 10:36:23 +00:00
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 " ) ) ;
2019-08-30 10:06:41 +00:00
proposal_create_operation pcop1 = proposal_create_operation : : committee_proposal (
2018-12-12 10:36:23 +00:00
db . get_global_properties ( ) . parameters ,
2019-08-30 10:06:41 +00:00
db . head_block_time ( )
2018-12-12 10:36:23 +00:00
) ;
pcop1 . review_period_seconds . reset ( ) ;
proposal_create_operation pcop2 = pcop1 ;
2018-08-27 19:33:58 +00:00
trx . clear ( ) ;
2018-12-12 10:36:23 +00:00
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 ;
}
}
2018-07-04 16:31:32 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
2018-03-25 21:40:32 +00:00
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 ( )