From 5f8549ebca8ca85ce2f28b9837bb88c11eb0c339 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 23 Mar 2019 16:37:39 -0400 Subject: [PATCH 001/534] Use by_collateral when globally settling after hf We'd like to remove `by_price` index at some time in the future to improve performance, thus we should avoid using the index after the hardfork. https://github.com/bitshares/bitshares-core/issues/1669 --- libraries/chain/db_market.cpp | 51 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 3d42f9abc9..35b92067cf 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -62,34 +62,61 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett const asset_dynamic_data_object& mia_dyn = mia.dynamic_asset_data_id(*this); auto original_mia_supply = mia_dyn.current_supply; - const auto& call_price_index = get_index_type().indices().get(); - auto maint_time = get_dynamic_global_properties().next_maintenance_time; bool before_core_hardfork_342 = ( maint_time <= HARDFORK_CORE_342_TIME ); // better rounding + bool before_core_hardfork_1270 = ( maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue // cancel all call orders and accumulate it into collateral_gathered - auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) ); - auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) ); + const auto& call_index = get_index_type().indices(); + const auto& call_price_index = call_index.get(); + const auto& call_collateral_index = call_index.get(); + + auto call_min = price::min( bitasset.options.short_backing_asset, mia.id ); + auto call_max = price::max( bitasset.options.short_backing_asset, mia.id ); + + auto call_price_itr = call_price_index.begin(); + auto call_price_end = call_price_itr; + auto call_collateral_itr = call_collateral_index.begin(); + auto call_collateral_end = call_collateral_itr; + + if( before_core_hardfork_1270 ) + { + call_price_itr = call_price_index.lower_bound( call_min ); + call_price_end = call_price_index.upper_bound( call_max ); + } + else + { + call_collateral_itr = call_collateral_index.lower_bound( call_min ); + call_collateral_end = call_collateral_index.upper_bound( call_max ); + } + asset pays; - while( call_itr != call_end ) + while( ( before_core_hardfork_1270 && call_price_itr != call_price_end ) + || (!before_core_hardfork_1270 && call_collateral_itr != call_collateral_end ) ) { + const call_order_object& order = ( before_core_hardfork_1270 ? *call_price_itr : *call_collateral_itr ); + if( before_core_hardfork_1270 ) + ++call_price_itr; + else + ++call_collateral_itr; + if( before_core_hardfork_342 ) { - pays = call_itr->get_debt() * settlement_price; // round down, in favor of call order + pays = order.get_debt() * settlement_price; // round down, in favor of call order // Be here, the call order can be paying nothing if( pays.amount == 0 && !bitasset.is_prediction_market ) // TODO remove this warning after hard fork core-342 - wlog( "Something for nothing issue (#184, variant E) occurred at block #${block}", ("block",head_block_num()) ); + wlog( "Something for nothing issue (#184, variant E) occurred at block #${block}", + ("block",head_block_num()) ); } else - pays = call_itr->get_debt().multiply_and_round_up( settlement_price ); // round up, in favor of global settlement fund + pays = order.get_debt().multiply_and_round_up( settlement_price ); // round up in favor of global-settle fund - if( pays > call_itr->get_collateral() ) - pays = call_itr->get_collateral(); + if( pays > order.get_collateral() ) + pays = order.get_collateral(); collateral_gathered += pays; - const auto& order = *call_itr; - ++call_itr; + FC_ASSERT( fill_call_order( order, pays, order.get_debt(), settlement_price, true ) ); // call order is maker } From 6faa519351f55a5440d649f1d97394123e062318 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 24 Mar 2019 11:25:57 -0400 Subject: [PATCH 002/534] Rewrite globally_settle() with a template function The distinction before/after hardfork #1270 (Call price inconsistent when MCR changed) now looks clearer. https://github.com/bitshares/bitshares-core/issues/1669 --- libraries/chain/db_market.cpp | 55 +++++++++---------- .../chain/include/graphene/chain/database.hpp | 5 ++ 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 35b92067cf..f0066aa706 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -52,6 +52,26 @@ namespace graphene { namespace chain { namespace detail { * No more asset updates may be issued. */ void database::globally_settle_asset( const asset_object& mia, const price& settlement_price ) +{ + auto maint_time = get_dynamic_global_properties().next_maintenance_time; + bool before_core_hardfork_1270 = ( maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue + + const auto& call_index = get_index_type().indices(); + const auto& call_price_index = call_index.get(); + const auto& call_collateral_index = call_index.get(); + + if( before_core_hardfork_1270 ) + { + globally_settle_asset_impl( mia, settlement_price, call_price_index ); + } + else + { + globally_settle_asset_impl( mia, settlement_price, call_collateral_index ); + } +} + +template +void database::globally_settle_asset_impl( const asset_object& mia, const price& settlement_price, const IndexType& call_index ) { try { const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); FC_ASSERT( !bitasset.has_settlement(), "black swan already occurred, it should not happen again" ); @@ -64,41 +84,16 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett auto maint_time = get_dynamic_global_properties().next_maintenance_time; bool before_core_hardfork_342 = ( maint_time <= HARDFORK_CORE_342_TIME ); // better rounding - bool before_core_hardfork_1270 = ( maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue // cancel all call orders and accumulate it into collateral_gathered - const auto& call_index = get_index_type().indices(); - const auto& call_price_index = call_index.get(); - const auto& call_collateral_index = call_index.get(); - - auto call_min = price::min( bitasset.options.short_backing_asset, mia.id ); - auto call_max = price::max( bitasset.options.short_backing_asset, mia.id ); - - auto call_price_itr = call_price_index.begin(); - auto call_price_end = call_price_itr; - auto call_collateral_itr = call_collateral_index.begin(); - auto call_collateral_end = call_collateral_itr; - - if( before_core_hardfork_1270 ) - { - call_price_itr = call_price_index.lower_bound( call_min ); - call_price_end = call_price_index.upper_bound( call_max ); - } - else - { - call_collateral_itr = call_collateral_index.lower_bound( call_min ); - call_collateral_end = call_collateral_index.upper_bound( call_max ); - } + auto call_itr = call_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) ); + auto call_end = call_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) ); asset pays; - while( ( before_core_hardfork_1270 && call_price_itr != call_price_end ) - || (!before_core_hardfork_1270 && call_collateral_itr != call_collateral_end ) ) + while( call_itr != call_end ) { - const call_order_object& order = ( before_core_hardfork_1270 ? *call_price_itr : *call_collateral_itr ); - if( before_core_hardfork_1270 ) - ++call_price_itr; - else - ++call_collateral_itr; + const call_order_object& order = *call_itr; + ++call_itr; if( before_core_hardfork_342 ) { diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 437c50d8dd..e8295f3a6b 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -353,6 +353,11 @@ namespace graphene { namespace chain { void cancel_bid(const collateral_bid_object& bid, bool create_virtual_op = true); void execute_bid( const collateral_bid_object& bid, share_type debt_covered, share_type collateral_from_fund, const price_feed& current_feed ); + private: + template + void globally_settle_asset_impl( const asset_object& bitasset, const price& settle_price, const IndexType& call_index ); + + public: /** * @brief Process a new limit order through the markets * @param order The new order to process From a05858bda0536f9b4897886145f1451d4a6fda48 Mon Sep 17 00:00:00 2001 From: abitmore Date: Mon, 25 Mar 2019 09:58:46 -0400 Subject: [PATCH 003/534] Simplify code --- libraries/chain/db_market.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index f0066aa706..a5efe5c6c4 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -56,17 +56,15 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett auto maint_time = get_dynamic_global_properties().next_maintenance_time; bool before_core_hardfork_1270 = ( maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue - const auto& call_index = get_index_type().indices(); - const auto& call_price_index = call_index.get(); - const auto& call_collateral_index = call_index.get(); - if( before_core_hardfork_1270 ) { - globally_settle_asset_impl( mia, settlement_price, call_price_index ); + globally_settle_asset_impl( mia, settlement_price, + get_index_type().indices().get() ); } else { - globally_settle_asset_impl( mia, settlement_price, call_collateral_index ); + globally_settle_asset_impl( mia, settlement_price, + get_index_type().indices().get() ); } } From ce28360564f11bdd0f77daff5a8d815d1cdb3e0d Mon Sep 17 00:00:00 2001 From: abitmore Date: Mon, 25 Mar 2019 10:01:25 -0400 Subject: [PATCH 004/534] Wrap long lines --- libraries/chain/db_market.cpp | 4 +++- libraries/chain/include/graphene/chain/database.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index a5efe5c6c4..05c467eef3 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -69,7 +69,9 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett } template -void database::globally_settle_asset_impl( const asset_object& mia, const price& settlement_price, const IndexType& call_index ) +void database::globally_settle_asset_impl( const asset_object& mia, + const price& settlement_price, + const IndexType& call_index ) { try { const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); FC_ASSERT( !bitasset.has_settlement(), "black swan already occurred, it should not happen again" ); diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index e8295f3a6b..241d9906b5 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -355,7 +355,9 @@ namespace graphene { namespace chain { private: template - void globally_settle_asset_impl( const asset_object& bitasset, const price& settle_price, const IndexType& call_index ); + void globally_settle_asset_impl( const asset_object& bitasset, + const price& settle_price, + const IndexType& call_index ); public: /** From 54e6850332c0be14991fcc85214a8dfdb4175a7b Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Mon, 24 Jun 2019 17:59:49 +0200 Subject: [PATCH 005/534] Fixes #1692 --- libraries/chain/hardfork.d/CORE_1692.hf | 4 ++++ libraries/chain/market_evaluator.cpp | 22 +++++++++++++++------- tests/tests/swan_tests.cpp | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_1692.hf diff --git a/libraries/chain/hardfork.d/CORE_1692.hf b/libraries/chain/hardfork.d/CORE_1692.hf new file mode 100644 index 0000000000..cbbe42c4ae --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1692.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #1692 validation check of bid_collateral +#ifndef HARDFORK_CORE_1692_TIME +#define HARDFORK_CORE_1692_TIME (fc::time_point_sec( 1600000000 ) ) // Sep 2020 +#endif diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index 17d1164362..fa6b590632 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -391,13 +391,6 @@ void_result bid_collateral_evaluator::do_evaluate(const bid_collateral_operation FC_ASSERT( !_bitasset_data->is_prediction_market, "Cannot bid on a prediction market!" ); - if( o.additional_collateral.amount > 0 ) - { - FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= o.additional_collateral, - "Cannot bid ${c} collateral when payer only has ${b}", ("c", o.additional_collateral.amount) - ("b", d.get_balance(*_paying_account, o.additional_collateral.asset_id(d)).amount) ); - } - const collateral_bid_index& bids = d.get_index_type(); const auto& index = bids.indices().get(); const auto& bid = index.find( boost::make_tuple( o.debt_covered.asset_id, o.bidder ) ); @@ -406,6 +399,21 @@ void_result bid_collateral_evaluator::do_evaluate(const bid_collateral_operation else FC_ASSERT( o.debt_covered.amount > 0, "Can't find bid to cancel?!"); + if( o.additional_collateral.amount > 0 ) + { + if( _bid && d.head_block_time() >= HARDFORK_CORE_1692_TIME ) + { + asset delta = o.additional_collateral - _bid->get_additional_collateral(); + FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= delta, + "Cannot increase bid from ${oc} to ${nc} collateral when payer only has ${b}", + ("oc", _bid->get_additional_collateral().amount)("nc", o.additional_collateral.amount) + ("b", d.get_balance(*_paying_account, o.additional_collateral.asset_id(d)).amount) ); + } else + FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= o.additional_collateral, + "Cannot bid ${c} collateral when payer only has ${b}", ("c", o.additional_collateral.amount) + ("b", d.get_balance(*_paying_account, o.additional_collateral.asset_id(d)).amount) ); + } + return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } diff --git a/tests/tests/swan_tests.cpp b/tests/tests/swan_tests.cpp index 54f233c66a..c58c93238e 100644 --- a/tests/tests/swan_tests.cpp +++ b/tests/tests/swan_tests.cpp @@ -406,6 +406,28 @@ BOOST_AUTO_TEST_CASE( recollateralize ) } } +/** Creates a black swan, bid, adjust bid before/after hf_1692 + */ +BOOST_AUTO_TEST_CASE( bid_issue_1692 ) +{ try { + init_standard_swan( 700 ); + + generate_blocks( HARDFORK_CORE_1692_TIME - 30 ); + + int64_t b2_balance = get_balance( borrower2(), back() ); + bid_collateral( borrower2(), back().amount(1000), swan().amount(100) ); + BOOST_CHECK_EQUAL( get_balance( borrower2(), back() ), b2_balance - 1000 ); + GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance), swan().amount(200) ), fc::assert_exception ); + GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance-999), swan().amount(200) ), fc::assert_exception ); + + generate_blocks( HARDFORK_CORE_1692_TIME + 30 ); + + bid_collateral( borrower2(), back().amount(b2_balance-999), swan().amount(200) ); + BOOST_CHECK_EQUAL( get_balance( borrower2(), back() ), 999 ); + bid_collateral( borrower2(), back().amount(b2_balance), swan().amount(200) ); + BOOST_CHECK_EQUAL( get_balance( borrower2(), back() ), 0 ); +} FC_LOG_AND_RETHROW() } + /** Creates a black swan, settles all debts, recovers price feed - asset should be revived */ BOOST_AUTO_TEST_CASE( revive_empty_recovered ) From 73321cad4393cb20350efdd6971292da71d0a394 Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Mon, 8 Jul 2019 17:31:10 +0300 Subject: [PATCH 006/534] Added settle orders to market fee sharing program --- libraries/chain/db_market.cpp | 6 +- libraries/chain/hardfork.d/CORE_1780.hf | 4 + tests/tests/market_fee_sharing_tests.cpp | 1 - tests/tests/settle_tests.cpp | 189 +++++++++++++++++++++++ 4 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_1780.hf diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index c009d0b830..e309aec4b2 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -932,7 +932,11 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a { try { bool filled = false; - auto issuer_fees = pay_market_fees(get(receives.asset_id), receives); + const account_object& owner = settle.owner(*this); + + auto issuer_fees = ( head_block_time() < HARDFORK_CORE_1780_TIME ) ? + pay_market_fees(get(receives.asset_id), receives) : + pay_market_fees(owner, get(receives.asset_id), receives); if( pays < settle.balance ) { diff --git a/libraries/chain/hardfork.d/CORE_1780.hf b/libraries/chain/hardfork.d/CORE_1780.hf new file mode 100644 index 0000000000..8e1358b15b --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1780.hf @@ -0,0 +1,4 @@ +// Market fees of settle orders aren't shared to referral program +#ifndef HARDFORK_CORE_1780_TIME +#define HARDFORK_CORE_1780_TIME (fc::time_point_sec( 1600000000 ) ) // September 13, 2020 3:26:40 PM (GMT) +#endif diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 2ba95b2c5b..a267a3b9b5 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -426,7 +426,6 @@ BOOST_AUTO_TEST_CASE(create_actors) price price(asset(1, asset_id_type(1)), asset(1)); uint16_t market_fee_percent = 20 * GRAPHENE_1_PERCENT; - auto obj = jill_id(db); const asset_object jillcoin = create_user_issued_asset( "JCOIN", jill, charge_market_fee, price, 2, market_fee_percent ); const account_object alice = create_account("alice", izzyregistrar, izzyreferrer, 50/*0.5%*/); diff --git a/tests/tests/settle_tests.cpp b/tests/tests/settle_tests.cpp index f64719e613..1249c03eb9 100644 --- a/tests/tests/settle_tests.cpp +++ b/tests/tests/settle_tests.cpp @@ -1501,4 +1501,193 @@ BOOST_AUTO_TEST_CASE( global_settle_rounding_test_after_hf_184 ) } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( create_bitassets ) +{ + try { + generate_blocks( HARDFORK_1268_TIME ); + generate_blocks( db.get_dynamic_global_properties().next_maintenance_time ); + set_expiration( db, trx ); + + ACTORS((paul)(rachelregistrar)(rachelreferrer)); + + upgrade_to_lifetime_member(rachelregistrar); + upgrade_to_lifetime_member(rachelreferrer); + + constexpr auto market_fee_percent = 50 * GRAPHENE_1_PERCENT; + constexpr auto biteur_reward_percent = 90 * GRAPHENE_1_PERCENT; + constexpr auto referrer_reward_percent = 10 * GRAPHENE_1_PERCENT; + + const auto& biteur = create_bitasset( "EURBIT", paul_id, market_fee_percent, charge_market_fee, 2 ); + asset_id_type biteur_id = biteur.id; + + const auto& bitusd = create_bitasset( "USDBIT", paul_id, market_fee_percent, charge_market_fee, 2, biteur_id ); + + const account_object rachel = create_account( "rachel", rachelregistrar, rachelreferrer, referrer_reward_percent ); + + transfer( committee_account, rachelregistrar_id, asset( 10000000 ) ); + transfer( committee_account, rachelreferrer_id, asset( 10000000 ) ); + transfer( committee_account, rachel.get_id(), asset( 10000000) ); + transfer( committee_account, paul_id, asset( 10000000000 ) ); + + asset_update_operation op; + op.issuer = biteur.issuer; + op.asset_to_update = biteur_id; + op.new_options.issuer_permissions = charge_market_fee; + op.new_options.extensions.value.reward_percent = biteur_reward_percent; + op.new_options.flags = bitusd.options.flags | charge_market_fee; + op.new_options.core_exchange_rate = price( asset(20,biteur_id), asset(1,asset_id_type()) ); + op.new_options.market_fee_percent = market_fee_percent; + trx.operations.push_back(op); + sign(trx, paul_private_key); + PUSH_TX(db, trx); + generate_block(); + trx.clear(); + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_before_hardfork_1780 ) +{ + try { + INVOKE(create_bitassets); + + GET_ACTOR(paul); + GET_ACTOR(rachelregistrar); + GET_ACTOR(rachelreferrer); + + const asset_object &biteur = get_asset( "EURBIT" ); + asset_id_type biteur_id = biteur.id; + const asset_object &bitusd = get_asset( "USDBIT" ); + asset_id_type bitusd_id = bitusd.id; + + const auto& core = asset_id_type()(db); + + const account_object& rachel = get_account( "rachel" ); + + {// add a feed to asset bitusd + update_feed_producers( bitusd, {paul_id} ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(100), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + {// add a feed to asset biteur + update_feed_producers( biteur, {paul_id} ); + price_feed feed; + feed.settlement_price = price( biteur.amount(100), core.amount(5) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( biteur_id, paul_id, feed ); + } + + enable_fees(); + + // paul gets some bitusd and biteur + borrow( paul_id, biteur.amount(20000), core.amount(2000) ); + borrow( paul_id, bitusd.amount(10000), biteur.amount(1000) ); + + // and transfer some bitusd to rachel + constexpr auto rachel_bitusd_count = 1000; + transfer( paul_id, rachel.get_id(), asset(rachel_bitusd_count, bitusd_id) ); + + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); + generate_block(); + generate_blocks( db.head_block_time() + fc::hours(24) ); + + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_expected_result/2/*market fee percent = 50%*/ ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + BOOST_CHECK_EQUAL( rachelregistrar_reward, 0 ); + BOOST_CHECK_EQUAL( rachelreferrer_reward, 0 ); + + } FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE( market_fee_of_settle_order_after_hardfork_1780 ) +{ + try { + INVOKE(create_bitassets); + + GET_ACTOR(paul); + GET_ACTOR(rachelregistrar); + GET_ACTOR(rachelreferrer); + + const asset_object &biteur = get_asset( "EURBIT" ); + asset_id_type biteur_id = biteur.id; + const asset_object &bitusd = get_asset( "USDBIT" ); + asset_id_type bitusd_id = bitusd.id; + + const auto& core = asset_id_type()(db); + + const account_object& rachel = get_account( "rachel" ); + + generate_blocks( HARDFORK_CORE_1780_TIME ); + + {// add a feed to asset bitusd + update_feed_producers( bitusd, {paul_id} ); + price_feed feed; + feed.settlement_price = price( bitusd.amount(100), biteur.amount(5) ); + feed.core_exchange_rate = price( bitusd.amount(100), asset(1) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( bitusd_id, paul_id, feed ); + } + + {// add a feed to asset biteur + update_feed_producers( biteur, {paul_id} ); + price_feed feed; + feed.settlement_price = price( biteur.amount(100), core.amount(5) ); + feed.maintenance_collateral_ratio = 175 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + feed.maximum_short_squeeze_ratio = 110 * GRAPHENE_COLLATERAL_RATIO_DENOM / 100; + publish_feed( biteur_id, paul_id, feed ); + } + + enable_fees(); + + // paul gets some bitusd and biteur + borrow( paul_id, biteur.amount(20000), core.amount(2000) ); + borrow( paul_id, bitusd.amount(10000), biteur.amount(1000) ); + + // and transfer some bitusd to rachel + constexpr auto rachel_bitusd_count = 1000; + transfer( paul_id, rachel.get_id(), asset(rachel_bitusd_count, bitusd_id) ); + + force_settle( rachel, bitusd.amount(rachel_bitusd_count) ); + generate_block(); + generate_blocks( db.head_block_time() + fc::hours(24) ); + + // 1 biteur = 20 bitusd see publish_feed + const auto biteur_expected_result = rachel_bitusd_count/20; + BOOST_CHECK_EQUAL( get_balance(rachel, biteur), biteur_expected_result/2/*market fee percent = 50%*/ ); + BOOST_CHECK_EQUAL( get_balance(rachel, bitusd), 0 ); + + const auto rachelregistrar_reward = get_market_fee_reward( rachelregistrar, biteur ); + const auto rachelreferrer_reward = get_market_fee_reward( rachelreferrer, biteur ); + + BOOST_CHECK_GT( rachelregistrar_reward, 0 ); + BOOST_CHECK_GT( rachelreferrer_reward, 0 ); + + auto calculate_percent = [](const share_type& value, uint16_t percent) + { + auto a(value.value); + a *= percent; + a /= GRAPHENE_100_PERCENT; + return a; + }; + + const auto biteur_market_fee = calculate_percent( biteur_expected_result, 50 * GRAPHENE_1_PERCENT ); + const auto biteur_reward = calculate_percent( biteur_market_fee, 90*GRAPHENE_1_PERCENT ); + BOOST_CHECK_EQUAL( biteur_reward, rachelregistrar_reward + rachelreferrer_reward ); + + } FC_LOG_AND_RETHROW() +} + + BOOST_AUTO_TEST_SUITE_END() From 3ee53acd219051b447fc2ab77678097c0d805ded Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Fri, 28 Jun 2019 15:47:43 +0300 Subject: [PATCH 007/534] Too restrictive check in market fee sharing Created new hardfork Added unit tests --- libraries/chain/db_market.cpp | 7 +- libraries/chain/hardfork.d/CORE_1774.hf | 4 ++ tests/tests/market_fee_sharing_tests.cpp | 90 ++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 libraries/chain/hardfork.d/CORE_1774.hf diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index c009d0b830..9a02cac243 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -1246,7 +1246,12 @@ asset database::pay_market_fees(const account_object& seller, const asset_object if ( reward_value > 0 && is_authorized_asset(*this, seller.registrar(*this), recv_asset) ) { reward = recv_asset.amount(reward_value); - FC_ASSERT( reward < issuer_fees, "Market reward should be less than issuer fees"); + if( head_block_time() < HARDFORK_1774_TIME ){ + FC_ASSERT( reward < issuer_fees, "Market reward should be less than issuer fees"); + } + else{ + FC_ASSERT( reward <= issuer_fees, "Market reward should be less or equal than issuer fees"); + } // cut referrer percent from reward auto registrar_reward = reward; if( seller.referrer != seller.registrar ) diff --git a/libraries/chain/hardfork.d/CORE_1774.hf b/libraries/chain/hardfork.d/CORE_1774.hf new file mode 100644 index 0000000000..b53eced0be --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1774.hf @@ -0,0 +1,4 @@ +// #1774 Too restrictive check in market fee sharing +#ifndef HARDFORK_1774_TIME +#define HARDFORK_1774_TIME (fc::time_point_sec( 1600000000 ) ) // September 13, 2020 12:26:40 PM +#endif diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 2ba95b2c5b..b7d39a9e6d 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -96,6 +96,12 @@ struct reward_database_fixture : database_fixture database_fixture::generate_block(); } + void generate_blocks_past_hf1774() + { + database_fixture::generate_blocks( HARDFORK_1774_TIME ); + database_fixture::generate_block(); + } + asset core_asset(int64_t x ) { return asset( x*core_precision ); @@ -1002,4 +1008,88 @@ BOOST_AUTO_TEST_CASE( create_vesting_balance_object_test ) } FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(possibility_to_set_100_reward_percent_before_hf1774) +{ + try + { + INVOKE(create_actors); + + generate_blocks_past_hf1268(); + GET_ACTOR(jill); + + constexpr auto jillcoin_reward_percent = 100*GRAPHENE_1_PERCENT; + const asset_object &jillcoin = get_asset("JCOIN"); + + update_asset(jill_id, jill_private_key, jillcoin.get_id(), jillcoin_reward_percent); + + GET_ACTOR(izzyregistrar); + GET_ACTOR(izzyreferrer); + BOOST_CHECK_EQUAL( get_market_fee_reward( izzyregistrar, jillcoin ), 0 ); + BOOST_CHECK_EQUAL( get_market_fee_reward( izzyreferrer, jillcoin ), 0 ); + + GET_ACTOR(alice); + GET_ACTOR(bob); + // Alice and Bob place orders which match + create_sell_order( alice, jillcoin.amount(200000), core_asset(1) ); + GRAPHENE_REQUIRE_THROW( create_sell_order( bob, core_asset(1), jillcoin.amount(100000) );, fc::exception ); + } + FC_LOG_AND_RETHROW() +} + + +BOOST_AUTO_TEST_CASE( possibility_to_set_100_reward_percent_after_hf1774 ) +{ + try + { + INVOKE(create_actors); + + generate_blocks_past_hf1268(); + GET_ACTOR(jill); + + constexpr auto jillcoin_reward_percent = 100*GRAPHENE_1_PERCENT; + const asset_object &jillcoin = get_asset("JCOIN"); + + update_asset(jill_id, jill_private_key, jillcoin.get_id(), jillcoin_reward_percent); + + GET_ACTOR(izzyregistrar); + GET_ACTOR(izzyreferrer); + BOOST_CHECK_EQUAL( get_market_fee_reward( izzyregistrar, jillcoin ), 0 ); + BOOST_CHECK_EQUAL( get_market_fee_reward( izzyreferrer, jillcoin ), 0 ); + + GET_ACTOR(alice); + GET_ACTOR(bob); + + generate_blocks_past_hf1774(); + + const share_type sell_amount = 100000; + + // Alice and Bob place orders which match + create_sell_order( alice, jillcoin.amount(sell_amount), core_asset(1) ); + create_sell_order( bob, core_asset(1), jillcoin.amount(sell_amount) ); + + const auto izzyregistrar_reward = get_market_fee_reward( izzyregistrar, jillcoin ); + const auto izzyreferrer_reward = get_market_fee_reward( izzyreferrer, jillcoin ); + + BOOST_CHECK_GT(izzyregistrar_reward , 0); + BOOST_CHECK_GT(izzyreferrer_reward , 0); + + auto calculate_percent = [](const share_type& value, uint16_t percent) + { + auto a(value.value); + a *= percent; + a /= GRAPHENE_100_PERCENT; + return a; + }; + //jillcoin has 20% market fee percent, see create_actors + //all market fees are distributed between registrar and referrer + auto acc_rewards = izzyregistrar_reward + izzyreferrer_reward; + BOOST_CHECK_EQUAL( calculate_percent(sell_amount, 20*GRAPHENE_1_PERCENT), acc_rewards); + + //check referrer reward + BOOST_CHECK_EQUAL( calculate_percent(acc_rewards, alice.referrer_rewards_percentage), izzyreferrer_reward); + } + FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_SUITE_END() From 755812b9710395c03172cf1d78b1743ad38ea71b Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Thu, 11 Jul 2019 14:51:51 +0300 Subject: [PATCH 008/534] Move check of mfs-reward-percent from validator to evaluator --- libraries/chain/asset_evaluator.cpp | 13 ++++ libraries/chain/hardfork.d/CORE_1774.hf | 2 +- libraries/chain/proposal_evaluator.cpp | 7 +- libraries/protocol/asset_ops.cpp | 2 +- tests/tests/market_fee_sharing_tests.cpp | 92 +++++++++++++++--------- 5 files changed, 77 insertions(+), 39 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index e970790c7d..36e49def45 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -48,6 +48,17 @@ namespace detail { "Asset extension whitelist_market_fee_sharing is only available after HARDFORK_1268_TIME!"); } } + + // TODO review and remove code below and links to it after hf_1774 + void check_asset_options_hf_1774(const fc::time_point_sec& block_time, const asset_options& options) + { + if( block_time >= HARDFORK_1268_TIME && block_time < HARDFORK_1774_TIME ) + { + FC_ASSERT( !options.extensions.value.reward_percent.valid() || + *options.extensions.value.reward_percent < GRAPHENE_100_PERCENT, + "Asset extension reward percent must be less than 100% till HARDFORK_1774_TIME!"); + } + } } void_result asset_create_evaluator::do_evaluate( const asset_create_operation& op ) @@ -60,6 +71,7 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities ); detail::check_asset_options_hf_1268(d.head_block_time(), op.common_options); + detail::check_asset_options_hf_1774(d.head_block_time(), op.common_options); // Check that all authorities do exist for( auto id : op.common_options.whitelist_authorities ) @@ -289,6 +301,7 @@ void_result asset_update_evaluator::do_evaluate(const asset_update_operation& o) } detail::check_asset_options_hf_1268(d.head_block_time(), o.new_options); + detail::check_asset_options_hf_1774(d.head_block_time(), o.new_options); if( (d.head_block_time() < HARDFORK_572_TIME) || (a.dynamic_asset_data_id(d).current_supply != 0) ) { diff --git a/libraries/chain/hardfork.d/CORE_1774.hf b/libraries/chain/hardfork.d/CORE_1774.hf index b53eced0be..b0f5f7814b 100644 --- a/libraries/chain/hardfork.d/CORE_1774.hf +++ b/libraries/chain/hardfork.d/CORE_1774.hf @@ -1,4 +1,4 @@ -// #1774 Too restrictive check in market fee sharing +// #1774 Too restrictive check in market fee sharing #ifndef HARDFORK_1774_TIME #define HARDFORK_1774_TIME (fc::time_point_sec( 1600000000 ) ) // September 13, 2020 12:26:40 PM #endif diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 4e9a3ea656..5845177f3f 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -30,6 +30,7 @@ namespace graphene { namespace chain { namespace detail { void check_asset_options_hf_1268(const fc::time_point_sec& block_time, const asset_options& options); + void check_asset_options_hf_1774(const fc::time_point_sec& block_time, const asset_options& options); void check_vesting_balance_policy_hf_1268(const fc::time_point_sec& block_time, const vesting_policy_initializer& policy); } @@ -57,13 +58,15 @@ struct proposal_operation_hardfork_visitor && (*(v.delta_debt.asset_id( db ).bitasset_data_id))( db ).is_prediction_market ) , "Soft fork - preventing proposal with call_order_update!" ); } - // hf_1268 + // hf_1268 + hf_1774 void operator()(const graphene::chain::asset_create_operation &v) const { detail::check_asset_options_hf_1268(block_time, v.common_options); + detail::check_asset_options_hf_1774(block_time, v.common_options); } - // hf_1268 + // hf_1268 + hf_1774 void operator()(const graphene::chain::asset_update_operation &v) const { detail::check_asset_options_hf_1268(block_time, v.new_options); + detail::check_asset_options_hf_1774(block_time, v.new_options); } // hf_1268 void operator()(const graphene::chain::vesting_balance_create_operation &v) const { diff --git a/libraries/protocol/asset_ops.cpp b/libraries/protocol/asset_ops.cpp index ba1b7f65f8..202c79f4fc 100644 --- a/libraries/protocol/asset_ops.cpp +++ b/libraries/protocol/asset_ops.cpp @@ -239,7 +239,7 @@ void asset_options::validate()const FC_ASSERT( whitelist_markets.find(item) == whitelist_markets.end() ); } if( extensions.value.reward_percent.valid() ) - FC_ASSERT( *extensions.value.reward_percent < GRAPHENE_100_PERCENT ); + FC_ASSERT( *extensions.value.reward_percent <= GRAPHENE_100_PERCENT ); } void asset_claim_fees_operation::validate()const { diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index b7d39a9e6d..2aab3c49c3 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cannot_create_asset_with_additional_options_before_hf) FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(create_asset_with_additional_options_after_hf) +BOOST_AUTO_TEST_CASE(create_asset_with_additional_options_after_hf1268) { try { @@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(create_asset_with_additional_options_after_hf) FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(cannot_update_additional_options_before_hf) +BOOST_AUTO_TEST_CASE(cannot_update_additional_options_before_hf1268) { try { @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(cannot_update_additional_options_before_hf) FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(update_additional_options_after_hf) +BOOST_AUTO_TEST_CASE(update_additional_options_after_hf1268) { try { @@ -247,6 +247,59 @@ BOOST_AUTO_TEST_CASE(update_additional_options_after_hf) FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(create_asset_with_reward_percent_of_100_after_hf1774) +{ + try + { + ACTOR(issuer); + + generate_blocks_past_hf1774(); + + uint16_t reward_percent = GRAPHENE_100_PERCENT; // 100.00% + flat_set whitelist = {issuer_id}; + price price(asset(1, asset_id_type(1)), asset(1)); + uint16_t market_fee_percent = 100; + + additional_asset_options_t options; + options.value.reward_percent = reward_percent; + options.value.whitelist_market_fee_sharing = whitelist; + + asset_object usd_asset = create_user_issued_asset("USD", + issuer, + charge_market_fee, + price, + 2, + market_fee_percent, + options); + + additional_asset_options usd_options = usd_asset.options.extensions.value; + BOOST_CHECK_EQUAL(reward_percent, *usd_options.reward_percent); + BOOST_CHECK(whitelist == *usd_options.whitelist_market_fee_sharing); + } + FC_LOG_AND_RETHROW() +} + +BOOST_AUTO_TEST_CASE(set_reward_percent_to_100_after_hf1774) +{ + try + { + ACTOR(issuer); + + asset_object usd_asset = create_user_issued_asset("USD", issuer, charge_market_fee); + + generate_blocks_past_hf1774(); + + uint16_t reward_percent = GRAPHENE_100_PERCENT; // 100.00% + flat_set whitelist = {issuer_id}; + update_asset(issuer_id, issuer_private_key, usd_asset.get_id(), reward_percent, whitelist); + + additional_asset_options options = usd_asset.get_id()(db).options.extensions.value; + BOOST_CHECK_EQUAL(reward_percent, *options.reward_percent); + BOOST_CHECK(whitelist == *options.whitelist_market_fee_sharing); + } + FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_CASE(asset_rewards_test) { try @@ -1009,42 +1062,13 @@ BOOST_AUTO_TEST_CASE( create_vesting_balance_object_test ) } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(possibility_to_set_100_reward_percent_before_hf1774) -{ - try - { - INVOKE(create_actors); - - generate_blocks_past_hf1268(); - GET_ACTOR(jill); - - constexpr auto jillcoin_reward_percent = 100*GRAPHENE_1_PERCENT; - const asset_object &jillcoin = get_asset("JCOIN"); - - update_asset(jill_id, jill_private_key, jillcoin.get_id(), jillcoin_reward_percent); - - GET_ACTOR(izzyregistrar); - GET_ACTOR(izzyreferrer); - BOOST_CHECK_EQUAL( get_market_fee_reward( izzyregistrar, jillcoin ), 0 ); - BOOST_CHECK_EQUAL( get_market_fee_reward( izzyreferrer, jillcoin ), 0 ); - - GET_ACTOR(alice); - GET_ACTOR(bob); - // Alice and Bob place orders which match - create_sell_order( alice, jillcoin.amount(200000), core_asset(1) ); - GRAPHENE_REQUIRE_THROW( create_sell_order( bob, core_asset(1), jillcoin.amount(100000) );, fc::exception ); - } - FC_LOG_AND_RETHROW() -} - - BOOST_AUTO_TEST_CASE( possibility_to_set_100_reward_percent_after_hf1774 ) { try { INVOKE(create_actors); - generate_blocks_past_hf1268(); + generate_blocks_past_hf1774(); GET_ACTOR(jill); constexpr auto jillcoin_reward_percent = 100*GRAPHENE_1_PERCENT; @@ -1060,8 +1084,6 @@ BOOST_AUTO_TEST_CASE( possibility_to_set_100_reward_percent_after_hf1774 ) GET_ACTOR(alice); GET_ACTOR(bob); - generate_blocks_past_hf1774(); - const share_type sell_amount = 100000; // Alice and Bob place orders which match From c2b28e9917e9d4e11aef7e754f98ea0e283cc3a5 Mon Sep 17 00:00:00 2001 From: Alexey Frolov Date: Thu, 11 Jul 2019 16:46:36 +0300 Subject: [PATCH 009/534] optimize access to graphene database --- libraries/chain/db_market.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index e309aec4b2..53f6d97c8d 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -932,11 +932,9 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a { try { bool filled = false; - const account_object& owner = settle.owner(*this); - auto issuer_fees = ( head_block_time() < HARDFORK_CORE_1780_TIME ) ? pay_market_fees(get(receives.asset_id), receives) : - pay_market_fees(owner, get(receives.asset_id), receives); + pay_market_fees(settle.owner(*this), get(receives.asset_id), receives); if( pays < settle.balance ) { From 884fce43c7c761fb43ee24eafff18ecba02b0774 Mon Sep 17 00:00:00 2001 From: ddylko Date: Wed, 24 Jul 2019 13:50:59 +0300 Subject: [PATCH 010/534] fees forwarded from templ-acc to committee-acc --- libraries/chain/db_market.cpp | 8 ++- libraries/chain/hardfork.d/CORE_1800.hf | 4 ++ tests/tests/market_fee_sharing_tests.cpp | 79 ++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 libraries/chain/hardfork.d/CORE_1800.hf diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index c009d0b830..e0af516b00 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -1249,6 +1249,11 @@ asset database::pay_market_fees(const account_object& seller, const asset_object FC_ASSERT( reward < issuer_fees, "Market reward should be less than issuer fees"); // cut referrer percent from reward auto registrar_reward = reward; + + auto registrar = ( seller.registrar == GRAPHENE_TEMP_ACCOUNT && head_block_time() >= HARDFORK_CORE_1800_TIME ) + ? GRAPHENE_COMMITTEE_ACCOUNT + : seller.registrar; + if( seller.referrer != seller.registrar ) { const auto referrer_rewards_value = detail::calculate_percent( reward.amount, @@ -1263,7 +1268,8 @@ asset database::pay_market_fees(const account_object& seller, const asset_object deposit_market_fee_vesting_balance(seller.referrer, referrer_reward); } } - deposit_market_fee_vesting_balance(seller.registrar, registrar_reward); + deposit_market_fee_vesting_balance(registrar, registrar_reward); + } } } diff --git a/libraries/chain/hardfork.d/CORE_1800.hf b/libraries/chain/hardfork.d/CORE_1800.hf new file mode 100644 index 0000000000..06e4f5341a --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1800.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #1800 Fix "Temp-account market fee sharing" +#ifndef HARDFORK_CORE_1800_TIME +#define HARDFORK_CORE_1800_TIME (fc::time_point_sec( 1563888919 )) // Tue, 23 Jul 2019 13:35:00 UTC +#endif diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 2ba95b2c5b..8f6fdc0604 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -96,6 +96,18 @@ struct reward_database_fixture : database_fixture database_fixture::generate_block(); } + void generate_blocks_before_hf1800() + { + database_fixture::generate_blocks( HARDFORK_CORE_1800_TIME ); + // database_fixture::generate_block(); + } + + void generate_blocks_past_hf1800() + { + database_fixture::generate_blocks( HARDFORK_CORE_1800_TIME ); + database_fixture::generate_block(); + } + asset core_asset(int64_t x ) { return asset( x*core_precision ); @@ -431,18 +443,85 @@ BOOST_AUTO_TEST_CASE(create_actors) const account_object alice = create_account("alice", izzyregistrar, izzyreferrer, 50/*0.5%*/); const account_object bob = create_account("bob", izzyregistrar, izzyreferrer, 50/*0.5%*/); + const account_object old = create_account("old", GRAPHENE_TEMP_ACCOUNT(db), GRAPHENE_COMMITTEE_ACCOUNT(db), 50u); // prepare users' balance issue_uia( alice, jillcoin.amount( 20000000 ) ); transfer( committee_account, alice.get_id(), core_asset(1000) ); transfer( committee_account, bob.get_id(), core_asset(1000) ); + transfer( committee_account, old.get_id(), core_asset(1000) ); transfer( committee_account, izzyregistrar.get_id(), core_asset(1000) ); transfer( committee_account, izzyreferrer.get_id(), core_asset(1000) ); } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(MFS_before_hardfork_1800) +{ + try + { + INVOKE(create_actors); + + generate_blocks_before_hf1800(); + GET_ACTOR(jill); + + constexpr auto jillcoin_reward_percent = 2*GRAPHENE_1_PERCENT; + const asset_object &jillcoin = get_asset("JCOIN"); + + flat_set whitelist; + update_asset(jill_id, jill_private_key, jillcoin.get_id(), jillcoin_reward_percent, whitelist); + + BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + + GET_ACTOR(alice); + GET_ACTOR(old); + + create_sell_order( alice, jillcoin.amount(100000), core_asset(1) ); + create_sell_order( old, core_asset(1), jillcoin.amount(100000) ); + + BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + + } + FC_LOG_AND_RETHROW() + +} + +BOOST_AUTO_TEST_CASE(MFS_after_hardfork_1800) +{ + try + { + INVOKE(create_actors); + + generate_blocks_past_hf1800(); + GET_ACTOR(jill); + + constexpr auto jillcoin_reward_percent = 2*GRAPHENE_1_PERCENT; + const asset_object &jillcoin = get_asset("JCOIN"); + + flat_set whitelist; + update_asset(jill_id, jill_private_key, jillcoin.get_id(), jillcoin_reward_percent, whitelist); + + BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + + GET_ACTOR(alice); + GET_ACTOR(old); + + create_sell_order( alice, jillcoin.amount(100000), core_asset(1) ); + create_sell_order( old, core_asset(1), jillcoin.amount(100000) ); + + + BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + + } + FC_LOG_AND_RETHROW() + +} + BOOST_AUTO_TEST_CASE(white_list_is_empty_test) { try From d5076eee1ddbf05184f538b138144ab73afd609c Mon Sep 17 00:00:00 2001 From: ddylko Date: Thu, 25 Jul 2019 14:26:13 +0300 Subject: [PATCH 011/534] hf time fixes, tests names and cmp condition fixes --- libraries/chain/hardfork.d/CORE_1800.hf | 2 +- tests/tests/market_fee_sharing_tests.cpp | 18 ++++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/libraries/chain/hardfork.d/CORE_1800.hf b/libraries/chain/hardfork.d/CORE_1800.hf index 06e4f5341a..39d8334cc8 100644 --- a/libraries/chain/hardfork.d/CORE_1800.hf +++ b/libraries/chain/hardfork.d/CORE_1800.hf @@ -1,4 +1,4 @@ // bitshares-core issue #1800 Fix "Temp-account market fee sharing" #ifndef HARDFORK_CORE_1800_TIME -#define HARDFORK_CORE_1800_TIME (fc::time_point_sec( 1563888919 )) // Tue, 23 Jul 2019 13:35:00 UTC +#define HARDFORK_CORE_1800_TIME (fc::time_point_sec( 1600000000 )) // Tue, 23 Jul 2019 13:35:00 UTC #endif diff --git a/tests/tests/market_fee_sharing_tests.cpp b/tests/tests/market_fee_sharing_tests.cpp index 8f6fdc0604..378c8f63dc 100644 --- a/tests/tests/market_fee_sharing_tests.cpp +++ b/tests/tests/market_fee_sharing_tests.cpp @@ -96,12 +96,6 @@ struct reward_database_fixture : database_fixture database_fixture::generate_block(); } - void generate_blocks_before_hf1800() - { - database_fixture::generate_blocks( HARDFORK_CORE_1800_TIME ); - // database_fixture::generate_block(); - } - void generate_blocks_past_hf1800() { database_fixture::generate_blocks( HARDFORK_CORE_1800_TIME ); @@ -457,13 +451,13 @@ BOOST_AUTO_TEST_CASE(create_actors) FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(MFS_before_hardfork_1800) +BOOST_AUTO_TEST_CASE(fee_shares_between_temp_acc_and_committee_acc) { try { INVOKE(create_actors); - generate_blocks_before_hf1800(); + generate_blocks_past_hf1268(); GET_ACTOR(jill); constexpr auto jillcoin_reward_percent = 2*GRAPHENE_1_PERCENT; @@ -481,15 +475,15 @@ BOOST_AUTO_TEST_CASE(MFS_before_hardfork_1800) create_sell_order( alice, jillcoin.amount(100000), core_asset(1) ); create_sell_order( old, core_asset(1), jillcoin.amount(100000) ); - BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); - BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_GT( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_GT( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); } FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(MFS_after_hardfork_1800) +BOOST_AUTO_TEST_CASE(fee_do_not_shares_between_temp_acc_and_committee_acc) { try { @@ -515,7 +509,7 @@ BOOST_AUTO_TEST_CASE(MFS_after_hardfork_1800) BOOST_CHECK_EQUAL( get_market_fee_reward( GRAPHENE_TEMP_ACCOUNT(db), jillcoin), 0); - BOOST_CHECK_GE( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); + BOOST_CHECK_GT( get_market_fee_reward( GRAPHENE_COMMITTEE_ACCOUNT(db), jillcoin), 0); } FC_LOG_AND_RETHROW() From 9d04ddb79bff59f42d49e73f8878a57f3b232b02 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 25 May 2016 14:35:56 -0500 Subject: [PATCH 012/534] Resolve #210: [HF] Check authorities on custom_operation The required_auths field on custom_operation was being ignored during authority checking. This commit causes it to be checked correctly, and adds a unit test verifying as much. --- .../include/graphene/protocol/custom.hpp | 3 +++ tests/tests/authority_tests.cpp | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/libraries/protocol/include/graphene/protocol/custom.hpp b/libraries/protocol/include/graphene/protocol/custom.hpp index 8be5ab1e60..ff9912e159 100644 --- a/libraries/protocol/include/graphene/protocol/custom.hpp +++ b/libraries/protocol/include/graphene/protocol/custom.hpp @@ -51,6 +51,9 @@ namespace graphene { namespace protocol { account_id_type fee_payer()const { return payer; } void validate()const; share_type calculate_fee(const fee_parameters_type& k)const; + void get_required_active_authorities( flat_set& auths )const { + auths.insert(required_auths.begin(), required_auths.end()); + } }; } } // namespace graphene::protocol diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 4ffa93460e..c7efd8f303 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -1858,6 +1858,29 @@ BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture ) } } +BOOST_AUTO_TEST_CASE( custom_operation_required_auths ) { + try { + ACTORS((alice)(bob)); + fund(alice); + enable_fees(); + + signed_transaction trx; + custom_operation op; + op.payer = alice_id; + op.required_auths.insert(bob_id); + op.fee = op.calculate_fee(db.current_fee_schedule().get()); + trx.operations.emplace_back(op); + trx.set_expiration(db.head_block_time() + 30); + sign(trx, alice_private_key); + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx), tx_missing_active_auth); + sign(trx, bob_private_key); + PUSH_TX(db, trx); + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + BOOST_FIXTURE_TEST_CASE( owner_delegation_test, database_fixture ) { try { ACTORS( (alice)(bob) ); From 771e03806d2f83c6ee7ba4a72ccd599decd4e31b Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Fri, 1 Mar 2019 10:44:37 -0600 Subject: [PATCH 013/534] Ref #210: Add hardfork guards Hardfork guards are complex for this issue, because we can't access chain time in the operation's get_required_active_authorities() method. There was no apparent 'good' way to solve this, so I settled for a fairly nasty hack which seemed the least bad of bad options. Add a boolean parameter to the verify_authority() functions determining whether the custom_operation::required_auths field should be ignored or not, and call these functions setting the boolean appropriately for whether we have passed the hardfork or not. This works because chain time is available at the verify_authority() call sites. --- libraries/chain/db_block.cpp | 18 +++-- libraries/chain/hardfork.d/CORE_210.hf | 4 ++ libraries/chain/proposal_object.cpp | 11 +++ .../include/graphene/protocol/transaction.hpp | 33 +++++---- libraries/protocol/transaction.cpp | 39 +++++----- tests/tests/authority_tests.cpp | 71 +++++++++---------- 6 files changed, 102 insertions(+), 74 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_210.hf diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index ace071ec0d..a20acc780e 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -646,11 +646,19 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_CORE_584_TIME ); auto get_active = [&]( account_id_type id ) { return &id(*this).active; }; auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; }; - trx.verify_authority( chain_id, - get_active, - get_owner, - allow_non_immediate_owner, - get_global_properties().parameters.max_authority_depth ); + + // See bitshares-core issue #210 for discussion + // The custom_operation::get_required_active_authorities() method initially failed to report the authorities + // from the custom_operaton::required_auths field. This was a bug. It's a simple fix in that method, but the + // fix is a hardfork, and thus we need a hardfork guard. Since that method cannot access chain time, we must + // implement the guard here, and skip the call to get_required_active_authorities() prior to the hardfork. + // Therefore, if the head_block_time() is prior to the 210 hardfork, we ignore the required auths specified + // by the custom_operation. + bool ignore_custom_operation_required_auths = (head_block_time() <= HARDFORK_CORE_210_TIME); + + trx.verify_authority(chain_id, get_active, get_owner, allow_non_immediate_owner, + ignore_custom_operation_required_auths, + get_global_properties().parameters.max_authority_depth); } //Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is diff --git a/libraries/chain/hardfork.d/CORE_210.hf b/libraries/chain/hardfork.d/CORE_210.hf new file mode 100644 index 0000000000..deea4f0e43 --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_210.hf @@ -0,0 +1,4 @@ +// #210 Check authorities on custom_operation +#ifndef HARDFORK_CORE_210_TIME +#define HARDFORK_CORE_210_TIME (fc::time_point_sec(1893456000)) // Jan 1 00:00:00 2030 (Not yet scheduled) +#endif diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index 62502e2736..eebd18483b 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -33,12 +34,22 @@ bool proposal_object::is_authorized_to_execute(database& db) const transaction_evaluation_state dry_run_eval(&db); try { + // See bitshares-core issue #210 for discussion + // The custom_operation::get_required_active_authorities() method initially failed to report the authorities + // from the custom_operaton::required_auths field. This was a bug. It's a simple fix in that method, but the + // fix is a hardfork, and thus we need a hardfork guard. Since that method cannot access chain time, we must + // implement the guard here, and skip the call to get_required_active_authorities() prior to the hardfork. + // Therefore, if the head_block_time() is prior to the 210 hardfork, we ignore the required auths specified + // by the custom_operation. + bool ignore_custom_operation_required_auths = (db.head_block_time() <= HARDFORK_CORE_210_TIME); + bool allow_non_immediate_owner = ( db.head_block_time() >= HARDFORK_CORE_584_TIME ); verify_authority( proposed_transaction.operations, available_key_approvals, [&]( account_id_type id ){ return &id(db).active; }, [&]( account_id_type id ){ return &id(db).owner; }, allow_non_immediate_owner, + ignore_custom_operation_required_auths, db.get_global_properties().parameters.max_authority_depth, true, /* allow committee */ available_active_approvals, diff --git a/libraries/protocol/include/graphene/protocol/transaction.hpp b/libraries/protocol/include/graphene/protocol/transaction.hpp index 17b7874d41..5448bbea43 100644 --- a/libraries/protocol/include/graphene/protocol/transaction.hpp +++ b/libraries/protocol/include/graphene/protocol/transaction.hpp @@ -162,15 +162,17 @@ namespace graphene { namespace protocol { * @param get_owner callback function to retrieve owner authorities of a given account * @param allow_non_immediate_owner whether to allow owner authority of non-immediately * required accounts to authorize operations in the transaction + * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the + * required_auths field of custom_operation or not * @param max_recursion maximum level of recursion when verifying, since an account * can have another account in active authorities and/or owner authorities */ - void verify_authority( - const chain_id_type& chain_id, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const; + void verify_authority(const chain_id_type& chain_id, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths = false, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH)const; /** * This is a slower replacement for get_required_signatures() @@ -243,20 +245,23 @@ namespace graphene { namespace protocol { * @param get_owner callback function to retrieve owner authorities of a given account * @param allow_non_immediate_owner whether to allow owner authority of non-immediately * required accounts to authorize operations + * @param ignore_custom_operation_required_auths See issue #210; whether to ignore the + * required_auths field of custom_operation or not * @param max_recursion maximum level of recursion when verifying, since an account * can have another account in active authorities and/or owner authorities * @param allow_committee whether to allow the special "committee account" to authorize the operations * @param active_approvals accounts that approved the operations with their active authories * @param owner_approvals accounts that approved the operations with their owner authories */ - void verify_authority( const vector& ops, const flat_set& sigs, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH, - bool allow_committe = false, - const flat_set& active_aprovals = flat_set(), - const flat_set& owner_approvals = flat_set()); + void verify_authority(const vector& ops, const flat_set& sigs, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths = false, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH, + bool allow_committe = false, + const flat_set& active_aprovals = flat_set(), + const flat_set& owner_approvals = flat_set()); /** * @brief captures the result of evaluating the operations contained in the transaction diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index 42b1d8ee0f..9b50c6b692 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -264,21 +264,26 @@ struct sign_state }; -void verify_authority( const vector& ops, const flat_set& sigs, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion_depth, - bool allow_committe, - const flat_set& active_aprovals, - const flat_set& owner_approvals ) +void verify_authority(const vector& ops, const flat_set& sigs, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion_depth, + bool allow_committe, + const flat_set& active_aprovals, + const flat_set& owner_approvals) { try { flat_set required_active; flat_set required_owner; vector other; - for( const auto& op : ops ) - operation_get_required_authorities( op, required_active, required_owner, other ); + for (const auto& op : ops) { + if (op.which() == operation::tag::value && ignore_custom_operation_required_auths) + required_active.insert(op.get().fee_payer()); + else + operation_get_required_authorities( op, required_active, required_owner, other ); + } if( !allow_committe ) GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(), @@ -429,15 +434,15 @@ const flat_set& precomputable_transaction::get_signature_keys( return _signees; } -void signed_transaction::verify_authority( - const chain_id_type& chain_id, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion )const +void signed_transaction::verify_authority(const chain_id_type& chain_id, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion)const { try { graphene::protocol::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, - allow_non_immediate_owner, max_recursion ); + allow_non_immediate_owner, ignore_custom_operation_required_auths, max_recursion ); } FC_CAPTURE_AND_RETHROW( (*this) ) } } } // graphene::protocol diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index c7efd8f303..15dade43f8 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -1858,12 +1858,17 @@ BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture ) } } -BOOST_AUTO_TEST_CASE( custom_operation_required_auths ) { +BOOST_AUTO_TEST_CASE( custom_operation_required_auths_before_fork ) { try { ACTORS((alice)(bob)); fund(alice); enable_fees(); + if (db.head_block_time() >= HARDFORK_CORE_210_TIME) { + wlog("Unable to test custom_operation required auths before fork: hardfork already passed"); + return; + } + signed_transaction trx; custom_operation op; op.payer = alice_id; @@ -1872,52 +1877,42 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths ) { trx.operations.emplace_back(op); trx.set_expiration(db.head_block_time() + 30); sign(trx, alice_private_key); - GRAPHENE_REQUIRE_THROW(db.push_transaction(trx), tx_missing_active_auth); - sign(trx, bob_private_key); - PUSH_TX(db, trx); + // Op requires bob's authorization, but only alice signed. We're before the fork, so this should work anyways. + db.push_transaction(trx); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; } } -BOOST_FIXTURE_TEST_CASE( owner_delegation_test, database_fixture ) -{ try { - ACTORS( (alice)(bob) ); - - fc::ecc::private_key bob_active_key = fc::ecc::private_key::regenerate(fc::digest("bob_active")); - fc::ecc::private_key bob_owner_key = fc::ecc::private_key::regenerate(fc::digest("bob_owner")); - - trx.clear(); +BOOST_AUTO_TEST_CASE( custom_operation_required_auths_after_fork ) { + try { + ACTORS((alice)(bob)); + fund(alice); - // Make sure Bob has different keys - account_update_operation auo; - auo.account = bob_id; - auo.active = authority( 1, public_key_type(bob_active_key.get_public_key()), 1 ); - auo.owner = authority( 1, public_key_type(bob_owner_key.get_public_key()), 1 ); - trx.operations.push_back( auo ); - sign( trx, bob_private_key ); - PUSH_TX( db, trx ); - trx.clear(); + if (db.head_block_time() < HARDFORK_CORE_210_TIME) + generate_blocks(HARDFORK_CORE_210_TIME + 10); - // Delegate Alice's owner auth to herself and active auth to Bob - auo.account = alice_id; - auo.active = authority( 1, bob_id, 1 ); - auo.owner = authority( 1, alice_id, 1 ); - trx.operations.push_back( auo ); - sign( trx, alice_private_key ); - PUSH_TX( db, trx ); - trx.clear(); + enable_fees(); - // Now Bob has full control over Alice's account - auo.account = alice_id; - auo.active.reset(); - auo.owner = authority( 1, bob_id, 1 ); - trx.operations.push_back( auo ); - sign( trx, bob_active_key ); - PUSH_TX( db, trx ); - trx.clear(); -} FC_LOG_AND_RETHROW() } + signed_transaction trx; + custom_operation op; + op.payer = alice_id; + op.required_auths.insert(bob_id); + op.fee = op.calculate_fee(db.current_fee_schedule().get()); + trx.operations.emplace_back(op); + trx.set_expiration(db.head_block_time() + 30); + sign(trx, alice_private_key); + // Op require's bob's authorization, but only alice signed. This should throw. + GRAPHENE_REQUIRE_THROW(db.push_transaction(trx), tx_missing_active_auth); + sign(trx, bob_private_key); + // Now that bob has signed, it should work. + PUSH_TX(db, trx); + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} /// This test case reproduces https://github.com/bitshares/bitshares-core/issues/944 /// and https://github.com/bitshares/bitshares-core/issues/580 From 974c8b677a6144cb1e338f6bc6de6b50c97ecb98 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sun, 3 Mar 2019 18:17:08 -0600 Subject: [PATCH 014/534] Progress #210: Apply requested changes --- libraries/app/database_api.cpp | 100 +++++---- libraries/chain/db_block.cpp | 11 +- libraries/chain/db_notify.cpp | 61 +++--- libraries/chain/hardfork.d/CORE_210.hf | 2 + .../chain/include/graphene/chain/impacted.hpp | 15 +- .../graphene/chain/proposal_evaluator.hpp | 2 + libraries/chain/proposal_evaluator.cpp | 111 +++++----- libraries/chain/proposal_object.cpp | 11 +- .../account_history_plugin.cpp | 7 +- .../elasticsearch/elasticsearch_plugin.cpp | 7 +- .../include/graphene/protocol/operations.hpp | 9 +- .../include/graphene/protocol/transaction.hpp | 43 ++-- libraries/protocol/operations.cpp | 44 ++-- libraries/protocol/transaction.cpp | 90 ++++---- tests/tests/authority_tests.cpp | 202 ++++++++++++------ 15 files changed, 397 insertions(+), 318 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 6c12eeecf5..218479410f 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2268,65 +2268,71 @@ set
database_api::get_potential_address_signatures( const signed_transa return my->get_potential_address_signatures( trx ); } -set database_api_impl::get_potential_signatures( const signed_transaction& trx )const +set database_api_impl::get_potential_signatures(const signed_transaction& trx) const { - bool allow_non_immediate_owner = ( _db.head_block_time() >= HARDFORK_CORE_584_TIME ); + auto chain_time = _db.head_block_time(); + bool allow_non_immediate_owner = (chain_time >= HARDFORK_CORE_584_TIME); + bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); + set result; - trx.get_required_signatures( - _db.get_chain_id(), - flat_set(), - [&]( account_id_type id ) - { - const auto& auth = id(_db).active; - for( const auto& k : auth.get_keys() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id ) - { - const auto& auth = id(_db).owner; - for( const auto& k : auth.get_keys() ) - result.insert(k); - return &auth; - }, - allow_non_immediate_owner, - _db.get_global_properties().parameters.max_authority_depth - ); + auto get_active = [&](account_id_type id) { + const auto& auth = id(_db).active; + for (const auto& k : auth.get_keys()) + result.insert(k); + return &auth; + }; + auto get_owner = [&](account_id_type id) { + const auto& auth = id(_db).owner; + for (const auto& k : auth.get_keys()) + result.insert(k); + return &auth; + }; + + trx.get_required_signatures(_db.get_chain_id(), + flat_set(), + get_active, get_owner, + allow_non_immediate_owner, + ignore_custom_op_reqd_auths, + _db.get_global_properties().parameters.max_authority_depth); // Insert keys in required "other" authories flat_set required_active; flat_set required_owner; vector other; - trx.get_required_authorities( required_active, required_owner, other ); - for( const auto& auth : other ) - for( const auto& key : auth.get_keys() ) - result.insert( key ); + trx.get_required_authorities(required_active, required_owner, other, ignore_custom_op_reqd_auths); + for (const auto& auth : other) + for (const auto& key : auth.get_keys()) + result.insert(key); return result; } -set
database_api_impl::get_potential_address_signatures( const signed_transaction& trx )const +set
database_api_impl::get_potential_address_signatures(const signed_transaction& trx)const { + auto chain_time = _db.head_block_time(); + bool allow_non_immediate_owner = (chain_time >= HARDFORK_CORE_584_TIME); + bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); + set
result; - trx.get_required_signatures( - _db.get_chain_id(), - flat_set(), - [&]( account_id_type id ) - { - const auto& auth = id(_db).active; - for( const auto& k : auth.get_addresses() ) - result.insert(k); - return &auth; - }, - [&]( account_id_type id ) - { - const auto& auth = id(_db).owner; - for( const auto& k : auth.get_addresses() ) - result.insert(k); - return &auth; - }, - _db.get_global_properties().parameters.max_authority_depth - ); + auto get_active = [&](account_id_type id) { + const auto& auth = id(_db).active; + for (const auto& k : auth.get_addresses()) + result.insert(k); + return &auth; + }; + auto get_owner = [&](account_id_type id) { + const auto& auth = id(_db).owner; + for (const auto& k : auth.get_addresses()) + result.insert(k); + return &auth; + }; + + trx.get_required_signatures(_db.get_chain_id(), + flat_set(), + get_active, get_owner, + allow_non_immediate_owner, + ignore_custom_op_reqd_auths, + _db.get_global_properties().parameters.max_authority_depth); return result; } @@ -2365,7 +2371,7 @@ bool database_api_impl::verify_account_authority( const string& account_name_or_ graphene::chain::verify_authority(ops, keys, [this]( account_id_type id ){ return &id(_db).active; }, [this]( account_id_type id ){ return &id(_db).owner; }, - true ); + true, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(_db.head_block_time()) ); } catch (fc::exception& ex) { diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index a20acc780e..fe7b86c83a 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -647,17 +647,8 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx auto get_active = [&]( account_id_type id ) { return &id(*this).active; }; auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; }; - // See bitshares-core issue #210 for discussion - // The custom_operation::get_required_active_authorities() method initially failed to report the authorities - // from the custom_operaton::required_auths field. This was a bug. It's a simple fix in that method, but the - // fix is a hardfork, and thus we need a hardfork guard. Since that method cannot access chain time, we must - // implement the guard here, and skip the call to get_required_active_authorities() prior to the hardfork. - // Therefore, if the head_block_time() is prior to the 210 hardfork, we ignore the required auths specified - // by the custom_operation. - bool ignore_custom_operation_required_auths = (head_block_time() <= HARDFORK_CORE_210_TIME); - trx.verify_authority(chain_id, get_active, get_owner, allow_non_immediate_owner, - ignore_custom_operation_required_auths, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()), get_global_properties().parameters.max_authority_depth); } diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index d17bec6821..298461c05b 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -25,8 +25,13 @@ using namespace graphene::chain; struct get_impacted_account_visitor { flat_set& _impacted; - get_impacted_account_visitor( flat_set& impact ):_impacted(impact) {} - typedef void result_type; + bool _ignore_custom_op_reqd_auths; + + get_impacted_account_visitor(flat_set& impact, bool ignore_custom_operation_required_auths) + : _impacted(impact), _ignore_custom_op_reqd_auths(ignore_custom_operation_required_auths) + {} + + using result_type = void; void operator()( const transfer_operation& op ) { @@ -153,10 +158,10 @@ struct get_impacted_account_visitor { _impacted.insert( op.fee_payer() ); // fee_paying_account vector other; - for( const auto& proposed_op : op.proposed_ops ) - operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other ); - for( auto& o : other ) - add_authority_accounts( _impacted, o ); + for (const auto& proposed_op : op.proposed_ops) + operation_get_required_authorities(proposed_op.op, _impacted, _impacted, other, _ignore_custom_op_reqd_auths); + for (auto& o : other) + add_authority_accounts(_impacted, o); } void operator()( const proposal_update_operation& op ) { @@ -213,7 +218,9 @@ struct get_impacted_account_visitor } void operator()( const custom_operation& op ) { - _impacted.insert( op.fee_payer() ); // payer + _impacted.insert(op.fee_payer()); // payer + if (!_ignore_custom_op_reqd_auths) + _impacted.insert(op.required_auths.begin(), op.required_auths.end()); } void operator()( const assert_operation& op ) { @@ -283,20 +290,17 @@ struct get_impacted_account_visitor } }; -void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result ) -{ - get_impacted_account_visitor vtor = get_impacted_account_visitor( result ); - op.visit( vtor ); +void graphene::chain::operation_get_impacted_accounts(const operation& op, flat_set& result, bool ignore_custom_operation_required_auths) { + get_impacted_account_visitor vtor = get_impacted_account_visitor(result, ignore_custom_operation_required_auths); + op.visit(vtor); } -void graphene::chain::transaction_get_impacted_accounts( const transaction& tx, flat_set& result ) -{ - for( const auto& op : tx.operations ) - operation_get_impacted_accounts( op, result ); +void graphene::chain::transaction_get_impacted_accounts(const transaction& tx, flat_set& result, bool ignore_custom_operation_required_auths) { + for (const auto& op : tx.operations) + operation_get_impacted_accounts(op, result, ignore_custom_operation_required_auths); } -void get_relevant_accounts( const object* obj, flat_set& accounts ) -{ +void get_relevant_accounts(const object* obj, flat_set& accounts, bool ignore_custom_operation_required_auths) { if( obj->id.space() == protocol_ids ) { switch( (object_type)obj->id.type() ) @@ -342,12 +346,14 @@ void get_relevant_accounts( const object* obj, flat_set& accoun } case proposal_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - transaction_get_impacted_accounts( aobj->proposed_transaction, accounts ); + transaction_get_impacted_accounts(aobj->proposed_transaction, accounts, + ignore_custom_operation_required_auths); break; } case operation_history_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - operation_get_impacted_accounts( aobj->op, accounts ); + operation_get_impacted_accounts(aobj->op, accounts, + ignore_custom_operation_required_auths); break; } case withdraw_permission_object_type:{ const auto& aobj = dynamic_cast(obj); @@ -404,7 +410,8 @@ void get_relevant_accounts( const object* obj, flat_set& accoun } case impl_transaction_history_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - transaction_get_impacted_accounts( aobj->trx, accounts ); + transaction_get_impacted_accounts(aobj->trx, accounts, + ignore_custom_operation_required_auths); break; } case impl_blinded_balance_object_type:{ const auto& aobj = dynamic_cast(obj); @@ -458,6 +465,7 @@ void database::notify_changed_objects() if( _undo_db.enabled() ) { const auto& head_undo = _undo_db.head(); + auto chain_time = head_block_time(); // New if( !new_objects.empty() ) @@ -469,7 +477,8 @@ void database::notify_changed_objects() new_ids.push_back(item); auto obj = find_object(item); if(obj != nullptr) - get_relevant_accounts(obj, new_accounts_impacted); + get_relevant_accounts(obj, new_accounts_impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time)); } if( new_ids.size() ) @@ -484,7 +493,8 @@ void database::notify_changed_objects() for( const auto& item : head_undo.old_values ) { changed_ids.push_back(item.first); - get_relevant_accounts(item.second.get(), changed_accounts_impacted); + get_relevant_accounts(item.second.get(), changed_accounts_impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time)); } if( changed_ids.size() ) @@ -502,13 +512,14 @@ void database::notify_changed_objects() removed_ids.emplace_back( item.first ); auto obj = item.second.get(); removed.emplace_back( obj ); - get_relevant_accounts(obj, removed_accounts_impacted); + get_relevant_accounts(obj, removed_accounts_impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time)); } if( removed_ids.size() ) - GRAPHENE_TRY_NOTIFY( removed_objects, removed_ids, removed, removed_accounts_impacted) + GRAPHENE_TRY_NOTIFY(removed_objects, removed_ids, removed, removed_accounts_impacted) } } -} FC_CAPTURE_AND_LOG( (0) ) } +} FC_LOG_AND_RETHROW() } } } diff --git a/libraries/chain/hardfork.d/CORE_210.hf b/libraries/chain/hardfork.d/CORE_210.hf index deea4f0e43..0f28527475 100644 --- a/libraries/chain/hardfork.d/CORE_210.hf +++ b/libraries/chain/hardfork.d/CORE_210.hf @@ -1,4 +1,6 @@ // #210 Check authorities on custom_operation #ifndef HARDFORK_CORE_210_TIME #define HARDFORK_CORE_210_TIME (fc::time_point_sec(1893456000)) // Jan 1 00:00:00 2030 (Not yet scheduled) +// Bugfix: pre-HF 210, custom_operation's required_auths field was ignored. +#define MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time) (chain_time <= HARDFORK_CORE_210_TIME) #endif diff --git a/libraries/chain/include/graphene/chain/impacted.hpp b/libraries/chain/include/graphene/chain/impacted.hpp index 9d986cb8ab..e5b0ea35b7 100644 --- a/libraries/chain/include/graphene/chain/impacted.hpp +++ b/libraries/chain/include/graphene/chain/impacted.hpp @@ -30,13 +30,12 @@ namespace graphene { namespace chain { -void operation_get_impacted_accounts( - const graphene::chain::operation& op, - fc::flat_set& result ); +void operation_get_impacted_accounts(const graphene::chain::operation& op, + fc::flat_set& result, + bool ignore_custom_operation_required_auths); -void transaction_get_impacted_accounts( - const graphene::chain::transaction& tx, - fc::flat_set& result - ); +void transaction_get_impacted_accounts(const graphene::chain::transaction& tx, + fc::flat_set& result, + bool ignore_custom_operation_required_auths); -} } // graphene::app \ No newline at end of file +} } // graphene::app diff --git a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp index e18ddd4226..454fb7ff48 100644 --- a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp @@ -56,6 +56,8 @@ namespace graphene { namespace chain { object_id_type do_apply( const proposal_create_operation& o ); transaction _proposed_trx; + flat_set _required_active_auths; + flat_set _required_owner_auths; hardfork_visitor_1479 vtor_1479; }; diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 4e9a3ea656..a2033030e2 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -166,54 +166,54 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati // Calling the proposal hardfork visitor const fc::time_point_sec block_time = d.head_block_time(); - proposal_operation_hardfork_visitor vtor( d, block_time ); - vtor( o ); - if( block_time < HARDFORK_CORE_214_TIME ) - { // cannot be removed after hf, unfortunately + proposal_operation_hardfork_visitor vtor(d, block_time); + vtor(o); + if (block_time < HARDFORK_CORE_214_TIME) { + // cannot be removed after hf, unfortunately hardfork_visitor_214 hf214; for (const op_wrapper &op : o.proposed_ops) - op.op.visit( hf214 ); + op.op.visit(hf214); } - vtor_1479( o ); + vtor_1479(o); const auto& global_parameters = d.get_global_properties().parameters; - FC_ASSERT( o.expiration_time > block_time, "Proposal has already expired on creation." ); - FC_ASSERT( o.expiration_time <= block_time + global_parameters.maximum_proposal_lifetime, + FC_ASSERT (o.expiration_time > block_time, "Proposal has already expired on creation."); + FC_ASSERT (o.expiration_time <= block_time + global_parameters.maximum_proposal_lifetime, "Proposal expiration time is too far in the future."); - FC_ASSERT( !o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - block_time), - "Proposal review period must be less than its overall lifetime." ); - - { - // If we're dealing with the committee authority, make sure this transaction has a sufficient review period. - flat_set auths; - vector other; - for( auto& op : o.proposed_ops ) - { - operation_get_required_authorities(op.op, auths, auths, other); - } - - FC_ASSERT( other.size() == 0 ); // TODO: what about other??? - - if( auths.find(GRAPHENE_COMMITTEE_ACCOUNT) != auths.end() ) - { - GRAPHENE_ASSERT( - o.review_period_seconds.valid(), - proposal_create_review_period_required, - "Review period not given, but at least ${min} required", - ("min", global_parameters.committee_proposal_review_period) - ); - GRAPHENE_ASSERT( - *o.review_period_seconds >= global_parameters.committee_proposal_review_period, - proposal_create_review_period_insufficient, - "Review period of ${t} specified, but at least ${min} required", - ("t", *o.review_period_seconds) - ("min", global_parameters.committee_proposal_review_period) - ); - } + FC_ASSERT (!o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - block_time), + "Proposal review period must be less than its overall lifetime."); + + // Find all authorities required by the proposed operations + flat_set tmp_required_active_auths; + vector other; + for (auto& op : o.proposed_ops) { + operation_get_required_authorities(op.op, tmp_required_active_auths, _required_owner_auths, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(block_time)); + } + // All accounts which must provide both owner and active authority should be omitted from the active authority set; + // owner authority approval implies active authority approval. + std::set_difference(tmp_required_active_auths.begin(), tmp_required_active_auths.end(), + _required_owner_auths.begin(), _required_owner_auths.end(), + std::inserter(_required_active_auths, _required_active_auths.begin())); + + // TODO: what about other??? + FC_ASSERT (other.empty(), "Proposals containing operations requiring non-account authorities are not yet implemented."); + + // If we're dealing with the committee authority, make sure this transaction has a sufficient review period. + if (_required_active_auths.count(GRAPHENE_COMMITTEE_ACCOUNT) || _required_owner_auths.count(GRAPHENE_COMMITTEE_ACCOUNT)) { + GRAPHENE_ASSERT(o.review_period_seconds.valid(), + proposal_create_review_period_required, + "Review period not given, but at least ${min} required", + ("min", global_parameters.committee_proposal_review_period)); + GRAPHENE_ASSERT(*o.review_period_seconds >= global_parameters.committee_proposal_review_period, + proposal_create_review_period_insufficient, + "Review period of ${t} specified, but at least ${min} required", + ("t", *o.review_period_seconds) + ("min", global_parameters.committee_proposal_review_period)); } - for( const op_wrapper& op : o.proposed_ops ) + for (const op_wrapper& op : o.proposed_ops) _proposed_trx.operations.push_back(op.op); _proposed_trx.validate(); @@ -230,35 +230,24 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati proposal.proposed_transaction = _proposed_trx; proposal.expiration_time = o.expiration_time; proposal.proposer = o.fee_paying_account; - if( o.review_period_seconds ) + if (o.review_period_seconds) proposal.review_period_time = o.expiration_time - *o.review_period_seconds; //Populate the required approval sets - flat_set required_active; - vector other; - - // TODO: consider caching values from evaluate? - for( auto& op : _proposed_trx.operations ) - operation_get_required_authorities(op, required_active, proposal.required_owner_approvals, other); - - //All accounts which must provide both owner and active authority should be omitted from the active authority set; - //owner authority approval implies active authority approval. - std::set_difference(required_active.begin(), required_active.end(), - proposal.required_owner_approvals.begin(), proposal.required_owner_approvals.end(), - std::inserter(proposal.required_active_approvals, proposal.required_active_approvals.begin())); - - if( d.head_block_time() > HARDFORK_CORE_1479_TIME ) - FC_ASSERT( vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance, - "Cannot update/delete a proposal with a future id!" ); - else if( vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.max_update_instance ) - { + proposal.required_owner_approvals.insert(_required_owner_auths.begin(), _required_owner_auths.end()); + proposal.required_active_approvals.insert(_required_active_auths.begin(), _required_active_auths.end()); + + if (d.head_block_time() > HARDFORK_CORE_1479_TIME) + FC_ASSERT (vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance, + "Cannot update/delete a proposal with a future id!"); + else if (vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.max_update_instance) { // prevent approval transfer_operation top; top.from = GRAPHENE_NULL_ACCOUNT; top.to = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT; - top.amount = asset( GRAPHENE_MAX_SHARE_SUPPLY ); - proposal.proposed_transaction.operations.emplace_back( top ); - wlog( "Issue 1479: ${p}", ("p",proposal) ); + top.amount = asset(GRAPHENE_MAX_SHARE_SUPPLY); + proposal.proposed_transaction.operations.emplace_back(top); + wlog("Issue 1479: ${p}", ("p",proposal)); } }); diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index eebd18483b..d87e331d9e 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -34,22 +34,13 @@ bool proposal_object::is_authorized_to_execute(database& db) const transaction_evaluation_state dry_run_eval(&db); try { - // See bitshares-core issue #210 for discussion - // The custom_operation::get_required_active_authorities() method initially failed to report the authorities - // from the custom_operaton::required_auths field. This was a bug. It's a simple fix in that method, but the - // fix is a hardfork, and thus we need a hardfork guard. Since that method cannot access chain time, we must - // implement the guard here, and skip the call to get_required_active_authorities() prior to the hardfork. - // Therefore, if the head_block_time() is prior to the 210 hardfork, we ignore the required auths specified - // by the custom_operation. - bool ignore_custom_operation_required_auths = (db.head_block_time() <= HARDFORK_CORE_210_TIME); - bool allow_non_immediate_owner = ( db.head_block_time() >= HARDFORK_CORE_584_TIME ); verify_authority( proposed_transaction.operations, available_key_approvals, [&]( account_id_type id ){ return &id(db).active; }, [&]( account_id_type id ){ return &id(db).owner; }, allow_non_immediate_owner, - ignore_custom_operation_required_auths, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ), db.get_global_properties().parameters.max_authority_depth, true, /* allow committee */ available_active_approvals, diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index c3d0826077..95c36a1fe7 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -128,12 +129,14 @@ void account_history_plugin_impl::update_account_histories( const signed_block& // get the set of accounts this operation applies to flat_set impacted; vector other; - operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here + operation_get_required_authorities(op.op, impacted, impacted, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); // fee_payer is added here if( op.op.is_type< account_create_operation >() ) impacted.insert( op.result.get() ); else - graphene::chain::operation_get_impacted_accounts( op.op, impacted ); + operation_get_impacted_accounts(op.op, impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); for( auto& a : other ) for( auto& item : a.account_auths ) diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp index d6ee6d719a..cd19f0ca5f 100644 --- a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -154,12 +155,14 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b // get the set of accounts this operation applies to flat_set impacted; vector other; - operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here + operation_get_required_authorities(op.op, impacted, impacted, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); // fee_payer is added here if( op.op.is_type< account_create_operation >() ) impacted.insert( op.result.get() ); else - graphene::chain::operation_get_impacted_accounts( op.op, impacted ); + operation_get_impacted_accounts(op.op, impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); for( auto& a : other ) for( auto& item : a.account_auths ) diff --git a/libraries/protocol/include/graphene/protocol/operations.hpp b/libraries/protocol/include/graphene/protocol/operations.hpp index 3a603ebf64..7d9b45d2c7 100644 --- a/libraries/protocol/include/graphene/protocol/operations.hpp +++ b/libraries/protocol/include/graphene/protocol/operations.hpp @@ -112,10 +112,11 @@ namespace graphene { namespace protocol { * * @return a set of required authorities for @ref op */ - void operation_get_required_authorities( const operation& op, - flat_set& active, - flat_set& owner, - vector& other ); + void operation_get_required_authorities(const operation& op, + flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths); void operation_validate( const operation& op ); diff --git a/libraries/protocol/include/graphene/protocol/transaction.hpp b/libraries/protocol/include/graphene/protocol/transaction.hpp index 5448bbea43..fd63171cc1 100644 --- a/libraries/protocol/include/graphene/protocol/transaction.hpp +++ b/libraries/protocol/include/graphene/protocol/transaction.hpp @@ -109,9 +109,10 @@ namespace graphene { namespace protocol { return results; } - void get_required_authorities( flat_set& active, - flat_set& owner, - vector& other )const; + void get_required_authorities(flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths)const; virtual uint64_t get_packed_size()const; @@ -144,14 +145,13 @@ namespace graphene { namespace protocol { * signatures, but any non-minimal result will still pass * validation. */ - set get_required_signatures( - const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH - )const; + set get_required_signatures(const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_authorities, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH)const; /** * Checks whether signatures in this signed transaction are sufficient to authorize the transaction. @@ -171,7 +171,7 @@ namespace graphene { namespace protocol { const std::function& get_active, const std::function& get_owner, bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths = false, + bool ignore_custom_operation_required_auths, uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH)const; /** @@ -180,14 +180,13 @@ namespace graphene { namespace protocol { * some cases where get_required_signatures() returns a * non-minimal set. */ - set minimize_required_signatures( - const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH - ) const; + set minimize_required_signatures(const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH) const; /** * @brief Extract public keys from signatures with given chain ID. @@ -257,9 +256,9 @@ namespace graphene { namespace protocol { const std::function& get_active, const std::function& get_owner, bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths = false, + bool ignore_custom_operation_required_auths, uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH, - bool allow_committe = false, + bool allow_committee = false, const flat_set& active_aprovals = flat_set(), const flat_set& owner_approvals = flat_set()); diff --git a/libraries/protocol/operations.cpp b/libraries/protocol/operations.cpp index 8045ed3261..1c9c08f37d 100644 --- a/libraries/protocol/operations.cpp +++ b/libraries/protocol/operations.cpp @@ -59,24 +59,37 @@ struct operation_validator struct operation_get_required_auth { - typedef void result_type; + using result_type = void; flat_set& active; flat_set& owner; vector& other; + bool ignore_custom_op_reqd_auths; - operation_get_required_auth( flat_set& a, - flat_set& own, - vector& oth ):active(a),owner(own),other(oth){} + operation_get_required_auth(flat_set& a, + flat_set& own, + vector& oth, + bool ignore_custom_operation_required_auths) + : active(a), owner(own), other(oth), + ignore_custom_op_reqd_auths(ignore_custom_operation_required_auths) + {} template - void operator()( const T& v )const - { - active.insert( v.fee_payer() ); - v.get_required_active_authorities( active ); - v.get_required_owner_authorities( owner ); - v.get_required_authorities( other ); + void operator()(const T& v) const { + active.insert(v.fee_payer()); + v.get_required_active_authorities(active); + v.get_required_owner_authorities(owner); + v.get_required_authorities(other); + } + + void operator()(const custom_operation& op) const { + active.insert(op.fee_payer()); + if (!ignore_custom_op_reqd_auths) { + op.get_required_active_authorities(active); + op.get_required_owner_authorities(owner); + op.get_required_authorities(other); + } } }; @@ -85,12 +98,13 @@ void operation_validate( const operation& op ) op.visit( operation_validator() ); } -void operation_get_required_authorities( const operation& op, - flat_set& active, - flat_set& owner, - vector& other ) +void operation_get_required_authorities(const operation& op, + flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths) { - op.visit( operation_get_required_auth( active, owner, other ) ); + op.visit(operation_get_required_auth(active, owner, other, ignore_custom_operation_required_auths)); } } } // namespace graphene::protocol diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index 9b50c6b692..2644e568fa 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -99,14 +99,15 @@ void transaction::set_reference_block( const block_id_type& reference_block ) ref_block_prefix = reference_block._hash[1].value(); } -void transaction::get_required_authorities( flat_set& active, - flat_set& owner, - vector& other )const +void transaction::get_required_authorities(flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths)const { - for( const auto& op : operations ) - operation_get_required_authorities( op, active, owner, other ); - for( const auto& account : owner ) - active.erase( account ); + for (const auto& op : operations) + operation_get_required_authorities(op, active, owner, other, ignore_custom_operation_required_auths); + for (const auto& account : owner) + active.erase(account); } @@ -270,7 +271,7 @@ void verify_authority(const vector& ops, const flat_set& active_aprovals, const flat_set& owner_approvals) { try { @@ -279,13 +280,10 @@ void verify_authority(const vector& ops, const flat_set other; for (const auto& op : ops) { - if (op.which() == operation::tag::value && ignore_custom_operation_required_auths) - required_active.insert(op.get().fee_payer()); - else - operation_get_required_authorities( op, required_active, required_owner, other ); + operation_get_required_authorities(op, required_active, required_owner, other, ignore_custom_operation_required_auths); } - if( !allow_committe ) + if( !allow_committee ) GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(), invalid_committee_approval, "Committee account may only propose transactions" ); @@ -340,51 +338,52 @@ const flat_set& signed_transaction::get_signature_keys( const c } FC_CAPTURE_AND_RETHROW() } -set signed_transaction::get_required_signatures( - const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion_depth )const +set signed_transaction::get_required_signatures(const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_authorities, + uint32_t max_recursion_depth)const { flat_set required_active; flat_set required_owner; vector other; - get_required_authorities( required_active, required_owner, other ); + get_required_authorities(required_active, required_owner, other, ignore_custom_operation_required_authorities); - const flat_set& signature_keys = get_signature_keys( chain_id ); - sign_state s( signature_keys, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth, available_keys ); + const flat_set& signature_keys = get_signature_keys(chain_id); + sign_state s(signature_keys, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth, available_keys); - for( const auto& auth : other ) + for (const auto& auth : other) s.check_authority(&auth); - for( auto& owner : required_owner ) - s.check_authority( get_owner( owner ) ); - for( auto& active : required_active ) - s.check_authority( active ) || s.check_authority( get_owner( active ) ); + for (auto& owner : required_owner) + s.check_authority(get_owner(owner)); + for (auto& active : required_active) + s.check_authority(active) || s.check_authority(get_owner(active)); s.remove_unused_signatures(); set result; - for( auto& provided_sig : s.provided_signatures ) - if( available_keys.find( provided_sig.first ) != available_keys.end() - && signature_keys.find( provided_sig.first ) == signature_keys.end() ) - result.insert( provided_sig.first ); + for (auto& provided_sig : s.provided_signatures) + if (available_keys.find(provided_sig.first) != available_keys.end() + && signature_keys.find(provided_sig.first) == signature_keys.end()) + result.insert(provided_sig.first); return result; } set signed_transaction::minimize_required_signatures( - const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - uint32_t max_recursion - ) const + const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion )const { - set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion ); + set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, + ignore_custom_operation_required_auths, max_recursion ); flat_set< public_key_type > result( s.begin(), s.end() ); for( const public_key_type& k : s ) @@ -393,15 +392,16 @@ set signed_transaction::minimize_required_signatures( try { graphene::protocol::verify_authority( operations, result, get_active, get_owner, + ignore_custom_operation_required_auths, allow_non_immediate_owner, max_recursion ); continue; // element stays erased if verify_authority is ok } - catch( const tx_missing_owner_auth& e ) {} - catch( const tx_missing_active_auth& e ) {} - catch( const tx_missing_other_auth& e ) {} - result.insert( k ); + catch(const tx_missing_owner_auth& e) {} + catch(const tx_missing_active_auth& e) {} + catch(const tx_missing_other_auth& e) {} + result.insert(k); } - return set( result.begin(), result.end() ); + return set(result.begin(), result.end()); } const transaction_id_type& precomputable_transaction::id()const diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 15dade43f8..5ded8e6e36 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE( proposed_single_account ) { vector other; flat_set active_set, owner_set; - operation_get_required_authorities(op,active_set,owner_set,other); + operation_get_required_authorities(op, active_set, owner_set, other, false); BOOST_CHECK_EQUAL(active_set.size(), 1lu); BOOST_CHECK_EQUAL(owner_set.size(), 0lu); BOOST_CHECK_EQUAL(other.size(), 0lu); @@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE( proposed_single_account ) active_set.clear(); other.clear(); - operation_get_required_authorities(op.proposed_ops.front().op,active_set,owner_set,other); + operation_get_required_authorities(op.proposed_ops.front().op, active_set, owner_set, other, false); BOOST_CHECK_EQUAL(active_set.size(), 1lu); BOOST_CHECK_EQUAL(owner_set.size(), 0lu); BOOST_CHECK_EQUAL(other.size(), 0lu); @@ -1052,7 +1052,7 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture ) flat_set active_set, owner_set; vector others; - trx.get_required_authorities( active_set, owner_set, others ); + trx.get_required_authorities(active_set, owner_set, others, false); PUSH_TX( db, trx, skip ); @@ -1192,10 +1192,10 @@ BOOST_FIXTURE_TEST_CASE( get_required_signatures_test, database_fixture ) ) -> bool { //wdump( (tx)(available_keys) ); - set result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, false ); - set result_set2 = tx.get_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, true ); + set result_set = tx.get_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, false, false); + set result_set2 = tx.get_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, true, false); //wdump( (result_set)(result_set2)(ref_set) ); return result_set == ref_set && result_set2 == ref_set; } ; @@ -1309,10 +1309,10 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture ) ) -> bool { //wdump( (tx)(available_keys) ); - set result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, false ); - set result_set2 = tx.get_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, true ); + set result_set = tx.get_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, false, false); + set result_set2 = tx.get_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, true, false); //wdump( (result_set)(result_set2)(ref_set) ); return result_set == ref_set && result_set2 == ref_set; } ; @@ -1324,10 +1324,10 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture ) ) -> bool { //wdump( (tx)(available_keys) ); - set result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, false ); - set result_set2 = tx.minimize_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, true ); + set result_set = tx.minimize_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, false, false); + set result_set2 = tx.minimize_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, true, false); //wdump( (result_set)(result_set2)(ref_set) ); return result_set == ref_set && result_set2 == ref_set; } ; @@ -1346,11 +1346,11 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture ) BOOST_CHECK( chk( tx, { alice_public_key, bob_public_key }, { alice_public_key, bob_public_key } ) ); BOOST_CHECK( chk_min( tx, { alice_public_key, bob_public_key }, { alice_public_key } ) ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ), fc::exception ); sign( tx, alice_private_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); } catch(fc::exception& e) { @@ -1432,8 +1432,8 @@ BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture ) ) -> bool { //wdump( (tx)(available_keys) ); - set result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, - get_active, get_owner, after_hf_584 ); + set result_set = tx.get_required_signatures(db.get_chain_id(), available_keys, + get_active, get_owner, after_hf_584, false); //wdump( (result_set)(ref_set) ); return result_set == ref_set; } ; @@ -1549,87 +1549,87 @@ BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture ) BOOST_CHECK( chk( tx, true, { gavin_active_pub, gavin_owner_pub }, { gavin_active_pub } ) ); sign( tx, alice_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, alice_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, bob_owner_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, bob_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, cindy_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, cindy_active_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, daisy_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, daisy_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, edwin_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, edwin_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, frank_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, frank_active_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, gavin_owner_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), fc::exception ); + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), fc::exception ); GRAPHENE_REQUIRE_THROW( PUSH_TX( db, tx, database::skip_transaction_dupe_check ), fc::exception ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); sign( tx, gavin_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); PUSH_TX( db, tx, database::skip_transaction_dupe_check ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); tx.clear_signatures(); // proposal tests @@ -1861,7 +1861,7 @@ BOOST_FIXTURE_TEST_CASE( parent_owner_test, database_fixture ) BOOST_AUTO_TEST_CASE( custom_operation_required_auths_before_fork ) { try { ACTORS((alice)(bob)); - fund(alice); + fund(alice, asset(10000000)); enable_fees(); if (db.head_block_time() >= HARDFORK_CORE_210_TIME) { @@ -1879,6 +1879,34 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths_before_fork ) { sign(trx, alice_private_key); // Op requires bob's authorization, but only alice signed. We're before the fork, so this should work anyways. db.push_transaction(trx); + + // Now try the same thing, but with a proposal + proposal_create_operation pcop; + pcop.fee_paying_account = alice_id; + pcop.proposed_ops = {op_wrapper(op)}; + pcop.expiration_time = db.head_block_time() + 10; + pcop.fee = pcop.calculate_fee(db.current_fee_schedule().get()); + trx.operations = {pcop}; + trx.signatures.clear(); + sign(trx, alice_private_key); + proposal_id_type pid = db.push_transaction(trx).operation_results[0].get(); + + // Check bob is not listed as a required approver + BOOST_REQUIRE_EQUAL(pid(db).required_active_approvals.count(bob_id), 0); + + // Add alice's approval + proposal_update_operation puop; + puop.fee_paying_account = alice_id; + puop.proposal = pid; + puop.active_approvals_to_add = {alice_id}; + puop.fee = puop.calculate_fee(db.current_fee_schedule().get()); + trx.operations = {puop}; + trx.signatures.clear(); + sign(trx, alice_private_key); + db.push_transaction(trx); + + // The proposal should have processed. Check it's not still in the database + BOOST_REQUIRE_EQUAL(db.find(pid), nullptr); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; @@ -1888,7 +1916,7 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths_before_fork ) { BOOST_AUTO_TEST_CASE( custom_operation_required_auths_after_fork ) { try { ACTORS((alice)(bob)); - fund(alice); + fund(alice, asset(10000000)); if (db.head_block_time() < HARDFORK_CORE_210_TIME) generate_blocks(HARDFORK_CORE_210_TIME + 10); @@ -1908,6 +1936,46 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths_after_fork ) { sign(trx, bob_private_key); // Now that bob has signed, it should work. PUSH_TX(db, trx); + + // Now try the same thing, but with a proposal + proposal_create_operation pcop; + pcop.fee_paying_account = alice_id; + pcop.proposed_ops = {op_wrapper(op)}; + pcop.expiration_time = db.head_block_time() + 10; + pcop.fee = pcop.calculate_fee(db.current_fee_schedule().get()); + trx.operations = {pcop}; + trx.signatures.clear(); + sign(trx, alice_private_key); + proposal_id_type pid = db.push_transaction(trx).operation_results[0].get(); + + // Check bob is listed as a required approver + BOOST_REQUIRE_EQUAL(pid(db).required_active_approvals.count(bob_id), 1); + + // Add alice's approval + proposal_update_operation puop; + puop.fee_paying_account = alice_id; + puop.proposal = pid; + puop.active_approvals_to_add = {alice_id}; + puop.fee = puop.calculate_fee(db.current_fee_schedule().get()); + trx.operations = {puop}; + trx.signatures.clear(); + sign(trx, alice_private_key); + db.push_transaction(trx); + + // The proposal should not have processed without bob's approval. + // Check it's still in the database + BOOST_REQUIRE_EQUAL(pid(db).required_active_approvals.count(bob_id), 1); + + // Now add bob's approval + puop.active_approvals_to_add = {bob_id}; + trx.operations = {puop}; + trx.signatures.clear(); + sign(trx, alice_private_key); // Alice still pays fee + sign(trx, bob_private_key); + db.push_transaction(trx); + + // Now the proposal should have processed and been removed from the database + BOOST_REQUIRE_EQUAL(db.find(pid), nullptr); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; @@ -1968,29 +2036,29 @@ BOOST_FIXTURE_TEST_CASE( missing_owner_auth_test, database_fixture ) tx.operations.push_back( op ); // not signed, should throw tx_missing_owner_auth - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), graphene::chain::tx_missing_owner_auth ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ), graphene::chain::tx_missing_owner_auth ); // signed with alice's active key, should throw tx_missing_owner_auth sign( tx, alice_active_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), graphene::chain::tx_missing_owner_auth ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ), graphene::chain::tx_missing_owner_auth ); // signed with alice's owner key, should not throw tx.clear_signatures(); sign( tx, alice_owner_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); // signed with both alice's owner key and active key, // it does not throw due to https://github.com/bitshares/bitshares-core/issues/580 sign( tx, alice_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); // creating a transaction that needs active permission tx.clear(); @@ -1999,27 +2067,27 @@ BOOST_FIXTURE_TEST_CASE( missing_owner_auth_test, database_fixture ) tx.operations.push_back( op ); // not signed, should throw tx_missing_active_auth - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), graphene::chain::tx_missing_active_auth ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ), graphene::chain::tx_missing_active_auth ); // signed with alice's active key, should not throw sign( tx, alice_active_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); // signed with alice's owner key, should not throw tx.clear_signatures(); sign( tx, alice_owner_key ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ); - tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ); + tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ); // signed with both alice's owner key and active key, should throw tx_irrelevant_sig sign( tx, alice_active_key ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, false, false ), graphene::chain::tx_irrelevant_sig ); - GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true ), + GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, true, false ), graphene::chain::tx_irrelevant_sig ); } From d5503e28f50f619b0f44a2b8d0e7fe4dc00ad509 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 6 Mar 2019 11:25:12 -0600 Subject: [PATCH 015/534] Progress #210: Requested changes Mostly polish, but one mistake fix as well. --- libraries/app/database_api.cpp | 8 ++++---- libraries/chain/db_notify.cpp | 2 +- libraries/chain/proposal_evaluator.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 218479410f..664e629155 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2275,13 +2275,13 @@ set database_api_impl::get_potential_signatures(const signed_tr bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); set result; - auto get_active = [&](account_id_type id) { + auto get_active = [this, &result](account_id_type id) { const auto& auth = id(_db).active; for (const auto& k : auth.get_keys()) result.insert(k); return &auth; }; - auto get_owner = [&](account_id_type id) { + auto get_owner = [this, &result](account_id_type id) { const auto& auth = id(_db).owner; for (const auto& k : auth.get_keys()) result.insert(k); @@ -2314,13 +2314,13 @@ set
database_api_impl::get_potential_address_signatures(const signed_tr bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); set
result; - auto get_active = [&](account_id_type id) { + auto get_active = [this, &result](account_id_type id) { const auto& auth = id(_db).active; for (const auto& k : auth.get_addresses()) result.insert(k); return &auth; }; - auto get_owner = [&](account_id_type id) { + auto get_owner = [this, &result](account_id_type id) { const auto& auth = id(_db).owner; for (const auto& k : auth.get_addresses()) result.insert(k); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 298461c05b..e0b46730f6 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -520,6 +520,6 @@ void database::notify_changed_objects() GRAPHENE_TRY_NOTIFY(removed_objects, removed_ids, removed, removed_accounts_impacted) } } -} FC_LOG_AND_RETHROW() } +} FC_CAPTURE_AND_LOG( (0) ) } } } diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index a2033030e2..4f51e9091d 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -198,10 +198,12 @@ void_result proposal_create_evaluator::do_evaluate(const proposal_create_operati std::inserter(_required_active_auths, _required_active_auths.begin())); // TODO: what about other??? - FC_ASSERT (other.empty(), "Proposals containing operations requiring non-account authorities are not yet implemented."); + FC_ASSERT (other.empty(), + "Proposals containing operations requiring non-account authorities are not yet implemented."); // If we're dealing with the committee authority, make sure this transaction has a sufficient review period. - if (_required_active_auths.count(GRAPHENE_COMMITTEE_ACCOUNT) || _required_owner_auths.count(GRAPHENE_COMMITTEE_ACCOUNT)) { + if (_required_active_auths.count(GRAPHENE_COMMITTEE_ACCOUNT) || + _required_owner_auths.count(GRAPHENE_COMMITTEE_ACCOUNT)) { GRAPHENE_ASSERT(o.review_period_seconds.valid(), proposal_create_review_period_required, "Review period not given, but at least ${min} required", From a081fff7aa3b49ee39100f621741e357c62cdbdc Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 13 Mar 2019 10:08:26 -0600 Subject: [PATCH 016/534] Ref #210: More explicit lambda captures --- libraries/chain/db_block.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index fe7b86c83a..2abbca1b2d 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -644,8 +644,8 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx if( !(skip & skip_transaction_signatures) ) { bool allow_non_immediate_owner = ( head_block_time() >= HARDFORK_CORE_584_TIME ); - auto get_active = [&]( account_id_type id ) { return &id(*this).active; }; - auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; }; + auto get_active = [this]( account_id_type id ) { return &id(*this).active; }; + auto get_owner = [this]( account_id_type id ) { return &id(*this).owner; }; trx.verify_authority(chain_id, get_active, get_owner, allow_non_immediate_owner, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(head_block_time()), From 48a54573458411128cc8871668268b622b74fbf4 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 13 Mar 2019 11:03:01 -0600 Subject: [PATCH 017/534] Issue #210: Formatting and build fixes --- libraries/app/database_api.cpp | 74 ++++++------ libraries/chain/db_notify.cpp | 46 ++++---- .../chain/include/graphene/chain/impacted.hpp | 12 +- libraries/chain/proposal_evaluator.cpp | 97 ++++++++-------- libraries/chain/proposal_object.cpp | 10 +- .../account_history_plugin.cpp | 9 +- .../elasticsearch/elasticsearch_plugin.cpp | 9 +- .../include/graphene/protocol/custom.hpp | 2 +- .../include/graphene/protocol/operations.hpp | 10 +- .../include/graphene/protocol/transaction.hpp | 69 ++++++------ libraries/protocol/operations.cpp | 46 ++++---- libraries/protocol/transaction.cpp | 106 +++++++++--------- tests/tests/authority_tests.cpp | 4 +- 13 files changed, 253 insertions(+), 241 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 664e629155..2e6739814a 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2268,71 +2268,71 @@ set
database_api::get_potential_address_signatures( const signed_transa return my->get_potential_address_signatures( trx ); } -set database_api_impl::get_potential_signatures(const signed_transaction& trx) const +set database_api_impl::get_potential_signatures( const signed_transaction& trx )const { auto chain_time = _db.head_block_time(); - bool allow_non_immediate_owner = (chain_time >= HARDFORK_CORE_584_TIME); - bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); + bool allow_non_immediate_owner = ( chain_time >= HARDFORK_CORE_584_TIME ); + bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( chain_time ); set result; - auto get_active = [this, &result](account_id_type id) { - const auto& auth = id(_db).active; - for (const auto& k : auth.get_keys()) - result.insert(k); + auto get_active = [this, &result]( account_id_type id ){ + const auto& auth = id( _db ).active; + for( const auto& k : auth.get_keys() ) + result.insert( k ); return &auth; }; - auto get_owner = [this, &result](account_id_type id) { - const auto& auth = id(_db).owner; - for (const auto& k : auth.get_keys()) - result.insert(k); + auto get_owner = [this, &result]( account_id_type id ){ + const auto& auth = id( _db ).owner; + for( const auto& k : auth.get_keys() ) + result.insert( k ); return &auth; }; - trx.get_required_signatures(_db.get_chain_id(), - flat_set(), - get_active, get_owner, - allow_non_immediate_owner, - ignore_custom_op_reqd_auths, - _db.get_global_properties().parameters.max_authority_depth); + trx.get_required_signatures( _db.get_chain_id(), + flat_set(), + get_active, get_owner, + allow_non_immediate_owner, + ignore_custom_op_reqd_auths, + _db.get_global_properties().parameters.max_authority_depth ); // Insert keys in required "other" authories flat_set required_active; flat_set required_owner; vector other; - trx.get_required_authorities(required_active, required_owner, other, ignore_custom_op_reqd_auths); - for (const auto& auth : other) - for (const auto& key : auth.get_keys()) - result.insert(key); + trx.get_required_authorities( required_active, required_owner, other, ignore_custom_op_reqd_auths ); + for( const auto& auth : other ) + for( const auto& key : auth.get_keys() ) + result.insert( key ); return result; } -set
database_api_impl::get_potential_address_signatures(const signed_transaction& trx)const +set
database_api_impl::get_potential_address_signatures( const signed_transaction& trx )const { auto chain_time = _db.head_block_time(); - bool allow_non_immediate_owner = (chain_time >= HARDFORK_CORE_584_TIME); - bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(chain_time); + bool allow_non_immediate_owner = ( chain_time >= HARDFORK_CORE_584_TIME ); + bool ignore_custom_op_reqd_auths = MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( chain_time ); set
result; - auto get_active = [this, &result](account_id_type id) { - const auto& auth = id(_db).active; - for (const auto& k : auth.get_addresses()) - result.insert(k); + auto get_active = [this, &result]( account_id_type id ){ + const auto& auth = id( _db ).active; + for( const auto& k : auth.get_addresses() ) + result.insert( k ); return &auth; }; - auto get_owner = [this, &result](account_id_type id) { - const auto& auth = id(_db).owner; + auto get_owner = [this, &result]( account_id_type id ) { + const auto& auth = id( _db ).owner; for (const auto& k : auth.get_addresses()) - result.insert(k); + result.insert( k ); return &auth; }; - trx.get_required_signatures(_db.get_chain_id(), - flat_set(), - get_active, get_owner, - allow_non_immediate_owner, - ignore_custom_op_reqd_auths, - _db.get_global_properties().parameters.max_authority_depth); + trx.get_required_signatures( _db.get_chain_id(), + flat_set(), + get_active, get_owner, + allow_non_immediate_owner, + ignore_custom_op_reqd_auths, + _db.get_global_properties().parameters.max_authority_depth ); return result; } diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index e0b46730f6..791367267d 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -27,8 +27,8 @@ struct get_impacted_account_visitor flat_set& _impacted; bool _ignore_custom_op_reqd_auths; - get_impacted_account_visitor(flat_set& impact, bool ignore_custom_operation_required_auths) - : _impacted(impact), _ignore_custom_op_reqd_auths(ignore_custom_operation_required_auths) + get_impacted_account_visitor( flat_set& impact, bool ignore_custom_operation_required_auths ) + : _impacted( impact ), _ignore_custom_op_reqd_auths( ignore_custom_operation_required_auths ) {} using result_type = void; @@ -158,10 +158,10 @@ struct get_impacted_account_visitor { _impacted.insert( op.fee_payer() ); // fee_paying_account vector other; - for (const auto& proposed_op : op.proposed_ops) - operation_get_required_authorities(proposed_op.op, _impacted, _impacted, other, _ignore_custom_op_reqd_auths); - for (auto& o : other) - add_authority_accounts(_impacted, o); + for( const auto& proposed_op : op.proposed_ops ) + operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other, _ignore_custom_op_reqd_auths ); + for( auto& o : other ) + add_authority_accounts( _impacted, o ); } void operator()( const proposal_update_operation& op ) { @@ -218,9 +218,9 @@ struct get_impacted_account_visitor } void operator()( const custom_operation& op ) { - _impacted.insert(op.fee_payer()); // payer - if (!_ignore_custom_op_reqd_auths) - _impacted.insert(op.required_auths.begin(), op.required_auths.end()); + _impacted.insert( op.fee_payer() ); // payer + if( !_ignore_custom_op_reqd_auths ) + _impacted.insert( op.required_auths.begin(), op.required_auths.end() ); } void operator()( const assert_operation& op ) { @@ -290,17 +290,17 @@ struct get_impacted_account_visitor } }; -void graphene::chain::operation_get_impacted_accounts(const operation& op, flat_set& result, bool ignore_custom_operation_required_auths) { - get_impacted_account_visitor vtor = get_impacted_account_visitor(result, ignore_custom_operation_required_auths); - op.visit(vtor); +void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result, bool ignore_custom_operation_required_auths ) { + get_impacted_account_visitor vtor = get_impacted_account_visitor( result, ignore_custom_operation_required_auths ); + op.visit( vtor ); } -void graphene::chain::transaction_get_impacted_accounts(const transaction& tx, flat_set& result, bool ignore_custom_operation_required_auths) { - for (const auto& op : tx.operations) - operation_get_impacted_accounts(op, result, ignore_custom_operation_required_auths); +void graphene::chain::transaction_get_impacted_accounts( const transaction& tx, flat_set& result, bool ignore_custom_operation_required_auths ) { + for( const auto& op : tx.operations ) + operation_get_impacted_accounts( op, result, ignore_custom_operation_required_auths ); } -void get_relevant_accounts(const object* obj, flat_set& accounts, bool ignore_custom_operation_required_auths) { +void get_relevant_accounts( const object* obj, flat_set& accounts, bool ignore_custom_operation_required_auths ) { if( obj->id.space() == protocol_ids ) { switch( (object_type)obj->id.type() ) @@ -346,14 +346,14 @@ void get_relevant_accounts(const object* obj, flat_set& account } case proposal_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - transaction_get_impacted_accounts(aobj->proposed_transaction, accounts, - ignore_custom_operation_required_auths); + transaction_get_impacted_accounts( aobj->proposed_transaction, accounts, + ignore_custom_operation_required_auths ); break; } case operation_history_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - operation_get_impacted_accounts(aobj->op, accounts, - ignore_custom_operation_required_auths); + operation_get_impacted_accounts( aobj->op, accounts, + ignore_custom_operation_required_auths ); break; } case withdraw_permission_object_type:{ const auto& aobj = dynamic_cast(obj); @@ -410,8 +410,8 @@ void get_relevant_accounts(const object* obj, flat_set& account } case impl_transaction_history_object_type:{ const auto& aobj = dynamic_cast(obj); FC_ASSERT( aobj != nullptr ); - transaction_get_impacted_accounts(aobj->trx, accounts, - ignore_custom_operation_required_auths); + transaction_get_impacted_accounts( aobj->trx, accounts, + ignore_custom_operation_required_auths ); break; } case impl_blinded_balance_object_type:{ const auto& aobj = dynamic_cast(obj); @@ -517,7 +517,7 @@ void database::notify_changed_objects() } if( removed_ids.size() ) - GRAPHENE_TRY_NOTIFY(removed_objects, removed_ids, removed, removed_accounts_impacted) + GRAPHENE_TRY_NOTIFY( removed_objects, removed_ids, removed, removed_accounts_impacted ) } } } FC_CAPTURE_AND_LOG( (0) ) } diff --git a/libraries/chain/include/graphene/chain/impacted.hpp b/libraries/chain/include/graphene/chain/impacted.hpp index e5b0ea35b7..6bb43048ac 100644 --- a/libraries/chain/include/graphene/chain/impacted.hpp +++ b/libraries/chain/include/graphene/chain/impacted.hpp @@ -30,12 +30,12 @@ namespace graphene { namespace chain { -void operation_get_impacted_accounts(const graphene::chain::operation& op, - fc::flat_set& result, - bool ignore_custom_operation_required_auths); +void operation_get_impacted_accounts( const graphene::chain::operation& op, + fc::flat_set& result, + bool ignore_custom_operation_required_auths ); -void transaction_get_impacted_accounts(const graphene::chain::transaction& tx, - fc::flat_set& result, - bool ignore_custom_operation_required_auths); +void transaction_get_impacted_accounts( const graphene::chain::transaction& tx, + fc::flat_set& result, + bool ignore_custom_operation_required_auths ); } } // graphene::app diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 4f51e9091d..39f838183a 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -160,103 +160,108 @@ void hardfork_visitor_1479::operator()(const graphene::chain::proposal_create_op op.op.visit(*this); } -void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o) +void_result proposal_create_evaluator::do_evaluate( const proposal_create_operation& o ) { try { const database& d = db(); // Calling the proposal hardfork visitor const fc::time_point_sec block_time = d.head_block_time(); - proposal_operation_hardfork_visitor vtor(d, block_time); - vtor(o); - if (block_time < HARDFORK_CORE_214_TIME) { + proposal_operation_hardfork_visitor vtor( d, block_time ); + vtor( o ); + if( block_time < HARDFORK_CORE_214_TIME ) + { // cannot be removed after hf, unfortunately hardfork_visitor_214 hf214; - for (const op_wrapper &op : o.proposed_ops) - op.op.visit(hf214); + for( const op_wrapper &op : o.proposed_ops ) + op.op.visit( hf214 ); } - vtor_1479(o); + vtor_1479( o ); const auto& global_parameters = d.get_global_properties().parameters; - FC_ASSERT (o.expiration_time > block_time, "Proposal has already expired on creation."); - FC_ASSERT (o.expiration_time <= block_time + global_parameters.maximum_proposal_lifetime, - "Proposal expiration time is too far in the future."); - FC_ASSERT (!o.review_period_seconds || fc::seconds(*o.review_period_seconds) < (o.expiration_time - block_time), - "Proposal review period must be less than its overall lifetime."); + FC_ASSERT( o.expiration_time > block_time, "Proposal has already expired on creation." ); + FC_ASSERT( o.expiration_time <= block_time + global_parameters.maximum_proposal_lifetime, + "Proposal expiration time is too far in the future." ); + FC_ASSERT( !o.review_period_seconds || fc::seconds( *o.review_period_seconds ) < ( o.expiration_time - block_time ), + "Proposal review period must be less than its overall lifetime." ); // Find all authorities required by the proposed operations flat_set tmp_required_active_auths; vector other; - for (auto& op : o.proposed_ops) { - operation_get_required_authorities(op.op, tmp_required_active_auths, _required_owner_auths, other, - MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(block_time)); + for( auto& op : o.proposed_ops ) + { + operation_get_required_authorities( op.op, tmp_required_active_auths, _required_owner_auths, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( block_time ) ); } // All accounts which must provide both owner and active authority should be omitted from the active authority set; // owner authority approval implies active authority approval. - std::set_difference(tmp_required_active_auths.begin(), tmp_required_active_auths.end(), - _required_owner_auths.begin(), _required_owner_auths.end(), - std::inserter(_required_active_auths, _required_active_auths.begin())); + std::set_difference( tmp_required_active_auths.begin(), tmp_required_active_auths.end(), + _required_owner_auths.begin(), _required_owner_auths.end(), + std::inserter( _required_active_auths, _required_active_auths.begin() ) ); // TODO: what about other??? - FC_ASSERT (other.empty(), - "Proposals containing operations requiring non-account authorities are not yet implemented."); + FC_ASSERT ( other.empty(), + "Proposals containing operations requiring non-account authorities are not yet implemented." ); // If we're dealing with the committee authority, make sure this transaction has a sufficient review period. - if (_required_active_auths.count(GRAPHENE_COMMITTEE_ACCOUNT) || - _required_owner_auths.count(GRAPHENE_COMMITTEE_ACCOUNT)) { - GRAPHENE_ASSERT(o.review_period_seconds.valid(), - proposal_create_review_period_required, - "Review period not given, but at least ${min} required", - ("min", global_parameters.committee_proposal_review_period)); - GRAPHENE_ASSERT(*o.review_period_seconds >= global_parameters.committee_proposal_review_period, - proposal_create_review_period_insufficient, - "Review period of ${t} specified, but at least ${min} required", - ("t", *o.review_period_seconds) - ("min", global_parameters.committee_proposal_review_period)); + if( _required_active_auths.count( GRAPHENE_COMMITTEE_ACCOUNT ) || + _required_owner_auths.count( GRAPHENE_COMMITTEE_ACCOUNT ) ) + { + GRAPHENE_ASSERT( o.review_period_seconds.valid(), + proposal_create_review_period_required, + "Review period not given, but at least ${min} required", + ("min", global_parameters.committee_proposal_review_period) ); + GRAPHENE_ASSERT( *o.review_period_seconds >= global_parameters.committee_proposal_review_period, + proposal_create_review_period_insufficient, + "Review period of ${t} specified, but at least ${min} required", + ("t", *o.review_period_seconds) + ("min", global_parameters.committee_proposal_review_period) ); } - for (const op_wrapper& op : o.proposed_ops) - _proposed_trx.operations.push_back(op.op); + for( const op_wrapper& op : o.proposed_ops ) + _proposed_trx.operations.push_back( op.op ); _proposed_trx.validate(); return void_result(); } FC_CAPTURE_AND_RETHROW( (o) ) } -object_id_type proposal_create_evaluator::do_apply(const proposal_create_operation& o) +object_id_type proposal_create_evaluator::do_apply( const proposal_create_operation& o ) { try { database& d = db(); + auto chain_time = d.head_block_time(); - const proposal_object& proposal = d.create([&](proposal_object& proposal) { + const proposal_object& proposal = d.create( [&o, this, chain_time](proposal_object& proposal) { _proposed_trx.expiration = o.expiration_time; proposal.proposed_transaction = _proposed_trx; proposal.expiration_time = o.expiration_time; proposal.proposer = o.fee_paying_account; - if (o.review_period_seconds) + if( o.review_period_seconds ) proposal.review_period_time = o.expiration_time - *o.review_period_seconds; //Populate the required approval sets - proposal.required_owner_approvals.insert(_required_owner_auths.begin(), _required_owner_auths.end()); - proposal.required_active_approvals.insert(_required_active_auths.begin(), _required_active_auths.end()); + proposal.required_owner_approvals.insert( _required_owner_auths.begin(), _required_owner_auths.end() ); + proposal.required_active_approvals.insert( _required_active_auths.begin(), _required_active_auths.end() ); - if (d.head_block_time() > HARDFORK_CORE_1479_TIME) - FC_ASSERT (vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance, - "Cannot update/delete a proposal with a future id!"); - else if (vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.max_update_instance) { + if( chain_time > HARDFORK_CORE_1479_TIME ) + FC_ASSERT( vtor_1479.nested_update_count == 0 || proposal.id.instance() > vtor_1479.max_update_instance, + "Cannot update/delete a proposal with a future id!" ); + else if( vtor_1479.nested_update_count > 0 && proposal.id.instance() <= vtor_1479.max_update_instance ) + { // prevent approval transfer_operation top; top.from = GRAPHENE_NULL_ACCOUNT; top.to = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT; - top.amount = asset(GRAPHENE_MAX_SHARE_SUPPLY); - proposal.proposed_transaction.operations.emplace_back(top); - wlog("Issue 1479: ${p}", ("p",proposal)); + top.amount = asset( GRAPHENE_MAX_SHARE_SUPPLY ); + proposal.proposed_transaction.operations.emplace_back( top ); + wlog( "Issue 1479: ${p}", ("p",proposal) ); } }); return proposal.id; } FC_CAPTURE_AND_RETHROW( (o) ) } -void_result proposal_update_evaluator::do_evaluate(const proposal_update_operation& o) +void_result proposal_update_evaluator::do_evaluate( const proposal_update_operation& o ) { try { database& d = db(); diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index d87e331d9e..1b192d8475 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -29,16 +29,16 @@ namespace graphene { namespace chain { -bool proposal_object::is_authorized_to_execute(database& db) const +bool proposal_object::is_authorized_to_execute( database& db ) const { - transaction_evaluation_state dry_run_eval(&db); + transaction_evaluation_state dry_run_eval( &db ); try { bool allow_non_immediate_owner = ( db.head_block_time() >= HARDFORK_CORE_584_TIME ); - verify_authority( proposed_transaction.operations, + verify_authority( proposed_transaction.operations, available_key_approvals, - [&]( account_id_type id ){ return &id(db).active; }, - [&]( account_id_type id ){ return &id(db).owner; }, + [&db]( account_id_type id ){ return &id( db ).active; }, + [&db]( account_id_type id ){ return &id( db ).owner; }, allow_non_immediate_owner, MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ), db.get_global_properties().parameters.max_authority_depth, diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index 95c36a1fe7..2a6e62114e 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -129,14 +129,15 @@ void account_history_plugin_impl::update_account_histories( const signed_block& // get the set of accounts this operation applies to flat_set impacted; vector other; - operation_get_required_authorities(op.op, impacted, impacted, other, - MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); // fee_payer is added here + // fee payer is added here + operation_get_required_authorities( op.op, impacted, impacted, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) ); if( op.op.is_type< account_create_operation >() ) impacted.insert( op.result.get() ); else - operation_get_impacted_accounts(op.op, impacted, - MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); + operation_get_impacted_accounts( op.op, impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) ); for( auto& a : other ) for( auto& item : a.account_auths ) diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp index cd19f0ca5f..7987192754 100644 --- a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -155,14 +155,15 @@ bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b // get the set of accounts this operation applies to flat_set impacted; vector other; - operation_get_required_authorities(op.op, impacted, impacted, other, - MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); // fee_payer is added here + // fee_payer is added here + operation_get_required_authorities( op.op, impacted, impacted, other, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) ); if( op.op.is_type< account_create_operation >() ) impacted.insert( op.result.get() ); else - operation_get_impacted_accounts(op.op, impacted, - MUST_IGNORE_CUSTOM_OP_REQD_AUTHS(db.head_block_time())); + operation_get_impacted_accounts( op.op, impacted, + MUST_IGNORE_CUSTOM_OP_REQD_AUTHS( db.head_block_time() ) ); for( auto& a : other ) for( auto& item : a.account_auths ) diff --git a/libraries/protocol/include/graphene/protocol/custom.hpp b/libraries/protocol/include/graphene/protocol/custom.hpp index ff9912e159..59ef3757db 100644 --- a/libraries/protocol/include/graphene/protocol/custom.hpp +++ b/libraries/protocol/include/graphene/protocol/custom.hpp @@ -52,7 +52,7 @@ namespace graphene { namespace protocol { void validate()const; share_type calculate_fee(const fee_parameters_type& k)const; void get_required_active_authorities( flat_set& auths )const { - auths.insert(required_auths.begin(), required_auths.end()); + auths.insert( required_auths.begin(), required_auths.end() ); } }; diff --git a/libraries/protocol/include/graphene/protocol/operations.hpp b/libraries/protocol/include/graphene/protocol/operations.hpp index 7d9b45d2c7..f7ddc01a02 100644 --- a/libraries/protocol/include/graphene/protocol/operations.hpp +++ b/libraries/protocol/include/graphene/protocol/operations.hpp @@ -112,11 +112,11 @@ namespace graphene { namespace protocol { * * @return a set of required authorities for @ref op */ - void operation_get_required_authorities(const operation& op, - flat_set& active, - flat_set& owner, - vector& other, - bool ignore_custom_operation_required_auths); + void operation_get_required_authorities( const operation& op, + flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths ); void operation_validate( const operation& op ); diff --git a/libraries/protocol/include/graphene/protocol/transaction.hpp b/libraries/protocol/include/graphene/protocol/transaction.hpp index fd63171cc1..505c3bebef 100644 --- a/libraries/protocol/include/graphene/protocol/transaction.hpp +++ b/libraries/protocol/include/graphene/protocol/transaction.hpp @@ -109,10 +109,10 @@ namespace graphene { namespace protocol { return results; } - void get_required_authorities(flat_set& active, - flat_set& owner, - vector& other, - bool ignore_custom_operation_required_auths)const; + void get_required_authorities( flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths )const; virtual uint64_t get_packed_size()const; @@ -145,13 +145,14 @@ namespace graphene { namespace protocol { * signatures, but any non-minimal result will still pass * validation. */ - set get_required_signatures(const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_authorities, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH)const; + set get_required_signatures( + const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_authorities, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const; /** * Checks whether signatures in this signed transaction are sufficient to authorize the transaction. @@ -167,12 +168,13 @@ namespace graphene { namespace protocol { * @param max_recursion maximum level of recursion when verifying, since an account * can have another account in active authorities and/or owner authorities */ - void verify_authority(const chain_id_type& chain_id, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH)const; + void verify_authority( + const chain_id_type& chain_id, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const; /** * This is a slower replacement for get_required_signatures() @@ -180,13 +182,14 @@ namespace graphene { namespace protocol { * some cases where get_required_signatures() returns a * non-minimal set. */ - set minimize_required_signatures(const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH) const; + set minimize_required_signatures( + const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH) const; /** * @brief Extract public keys from signatures with given chain ID. @@ -252,15 +255,15 @@ namespace graphene { namespace protocol { * @param active_approvals accounts that approved the operations with their active authories * @param owner_approvals accounts that approved the operations with their owner authories */ - void verify_authority(const vector& ops, const flat_set& sigs, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths, - uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH, - bool allow_committee = false, - const flat_set& active_aprovals = flat_set(), - const flat_set& owner_approvals = flat_set()); + void verify_authority( const vector& ops, const flat_set& sigs, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH, + bool allow_committee = false, + const flat_set& active_aprovals = flat_set(), + const flat_set& owner_approvals = flat_set() ); /** * @brief captures the result of evaluating the operations contained in the transaction diff --git a/libraries/protocol/operations.cpp b/libraries/protocol/operations.cpp index 1c9c08f37d..dd3ea4961f 100644 --- a/libraries/protocol/operations.cpp +++ b/libraries/protocol/operations.cpp @@ -67,28 +67,28 @@ struct operation_get_required_auth bool ignore_custom_op_reqd_auths; - operation_get_required_auth(flat_set& a, - flat_set& own, - vector& oth, - bool ignore_custom_operation_required_auths) - : active(a), owner(own), other(oth), - ignore_custom_op_reqd_auths(ignore_custom_operation_required_auths) + operation_get_required_auth( flat_set& a, + flat_set& own, + vector& oth, + bool ignore_custom_operation_required_auths ) + : active( a ), owner( own ), other( oth ), + ignore_custom_op_reqd_auths( ignore_custom_operation_required_auths ) {} template - void operator()(const T& v) const { - active.insert(v.fee_payer()); - v.get_required_active_authorities(active); - v.get_required_owner_authorities(owner); - v.get_required_authorities(other); + void operator()( const T& v ) const { + active.insert( v.fee_payer() ); + v.get_required_active_authorities( active ); + v.get_required_owner_authorities( owner ); + v.get_required_authorities( other ); } - void operator()(const custom_operation& op) const { - active.insert(op.fee_payer()); - if (!ignore_custom_op_reqd_auths) { - op.get_required_active_authorities(active); - op.get_required_owner_authorities(owner); - op.get_required_authorities(other); + void operator()( const custom_operation& op ) const { + active.insert( op.fee_payer() ); + if( !ignore_custom_op_reqd_auths ) { + op.get_required_active_authorities( active ); + op.get_required_owner_authorities( owner ); + op.get_required_authorities( other ); } } }; @@ -98,13 +98,13 @@ void operation_validate( const operation& op ) op.visit( operation_validator() ); } -void operation_get_required_authorities(const operation& op, - flat_set& active, - flat_set& owner, - vector& other, - bool ignore_custom_operation_required_auths) +void operation_get_required_authorities( const operation& op, + flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths ) { - op.visit(operation_get_required_auth(active, owner, other, ignore_custom_operation_required_auths)); + op.visit( operation_get_required_auth( active, owner, other, ignore_custom_operation_required_auths ) ); } } } // namespace graphene::protocol diff --git a/libraries/protocol/transaction.cpp b/libraries/protocol/transaction.cpp index 2644e568fa..153bed7ea5 100644 --- a/libraries/protocol/transaction.cpp +++ b/libraries/protocol/transaction.cpp @@ -99,15 +99,15 @@ void transaction::set_reference_block( const block_id_type& reference_block ) ref_block_prefix = reference_block._hash[1].value(); } -void transaction::get_required_authorities(flat_set& active, - flat_set& owner, - vector& other, - bool ignore_custom_operation_required_auths)const +void transaction::get_required_authorities( flat_set& active, + flat_set& owner, + vector& other, + bool ignore_custom_operation_required_auths )const { - for (const auto& op : operations) - operation_get_required_authorities(op, active, owner, other, ignore_custom_operation_required_auths); - for (const auto& account : owner) - active.erase(account); + for( const auto& op : operations ) + operation_get_required_authorities( op, active, owner, other, ignore_custom_operation_required_auths ); + for( const auto& account : owner ) + active.erase( account ); } @@ -265,22 +265,23 @@ struct sign_state }; -void verify_authority(const vector& ops, const flat_set& sigs, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths, - uint32_t max_recursion_depth, - bool allow_committee, - const flat_set& active_aprovals, - const flat_set& owner_approvals) +void verify_authority( const vector& ops, const flat_set& sigs, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion_depth, + bool allow_committee, + const flat_set& active_aprovals, + const flat_set& owner_approvals ) { try { flat_set required_active; flat_set required_owner; vector other; - for (const auto& op : ops) { - operation_get_required_authorities(op, required_active, required_owner, other, ignore_custom_operation_required_auths); + for( const auto& op : ops ) { + operation_get_required_authorities( op, required_active, required_owner, other, + ignore_custom_operation_required_auths ); } if( !allow_committee ) @@ -338,37 +339,37 @@ const flat_set& signed_transaction::get_signature_keys( const c } FC_CAPTURE_AND_RETHROW() } -set signed_transaction::get_required_signatures(const chain_id_type& chain_id, - const flat_set& available_keys, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_authorities, - uint32_t max_recursion_depth)const +set signed_transaction::get_required_signatures( const chain_id_type& chain_id, + const flat_set& available_keys, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_authorities, + uint32_t max_recursion_depth )const { flat_set required_active; flat_set required_owner; vector other; - get_required_authorities(required_active, required_owner, other, ignore_custom_operation_required_authorities); + get_required_authorities( required_active, required_owner, other, ignore_custom_operation_required_authorities ); const flat_set& signature_keys = get_signature_keys(chain_id); - sign_state s(signature_keys, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth, available_keys); + sign_state s( signature_keys, get_active, get_owner, allow_non_immediate_owner, max_recursion_depth, available_keys ); - for (const auto& auth : other) - s.check_authority(&auth); - for (auto& owner : required_owner) - s.check_authority(get_owner(owner)); - for (auto& active : required_active) - s.check_authority(active) || s.check_authority(get_owner(active)); + for( const auto& auth : other ) + s.check_authority( &auth ); + for( auto& owner : required_owner ) + s.check_authority( get_owner( owner ) ); + for( auto& active : required_active ) + s.check_authority( active ) || s.check_authority( get_owner( active ) ); s.remove_unused_signatures(); set result; - for (auto& provided_sig : s.provided_signatures) - if (available_keys.find(provided_sig.first) != available_keys.end() - && signature_keys.find(provided_sig.first) == signature_keys.end()) - result.insert(provided_sig.first); + for( auto& provided_sig : s.provided_signatures ) + if( available_keys.find( provided_sig.first ) != available_keys.end() + && signature_keys.find( provided_sig.first ) == signature_keys.end() ) + result.insert( provided_sig.first ); return result; } @@ -392,16 +393,16 @@ set signed_transaction::minimize_required_signatures( try { graphene::protocol::verify_authority( operations, result, get_active, get_owner, - ignore_custom_operation_required_auths, - allow_non_immediate_owner, max_recursion ); + allow_non_immediate_owner,ignore_custom_operation_required_auths, + max_recursion ); continue; // element stays erased if verify_authority is ok } - catch(const tx_missing_owner_auth& e) {} - catch(const tx_missing_active_auth& e) {} - catch(const tx_missing_other_auth& e) {} - result.insert(k); + catch( const tx_missing_owner_auth& e ) {} + catch( const tx_missing_active_auth& e ) {} + catch( const tx_missing_other_auth& e ) {} + result.insert( k ); } - return set(result.begin(), result.end()); + return set( result.begin(), result.end() ); } const transaction_id_type& precomputable_transaction::id()const @@ -434,15 +435,16 @@ const flat_set& precomputable_transaction::get_signature_keys( return _signees; } -void signed_transaction::verify_authority(const chain_id_type& chain_id, - const std::function& get_active, - const std::function& get_owner, - bool allow_non_immediate_owner, - bool ignore_custom_operation_required_auths, - uint32_t max_recursion)const +void signed_transaction::verify_authority( const chain_id_type& chain_id, + const std::function& get_active, + const std::function& get_owner, + bool allow_non_immediate_owner, + bool ignore_custom_operation_required_auths, + uint32_t max_recursion )const { try { graphene::protocol::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, - allow_non_immediate_owner, ignore_custom_operation_required_auths, max_recursion ); + allow_non_immediate_owner, ignore_custom_operation_required_auths, + max_recursion ); } FC_CAPTURE_AND_RETHROW( (*this) ) } } } // graphene::protocol diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 5ded8e6e36..c5e4031fe3 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -1906,7 +1906,7 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths_before_fork ) { db.push_transaction(trx); // The proposal should have processed. Check it's not still in the database - BOOST_REQUIRE_EQUAL(db.find(pid), nullptr); + BOOST_REQUIRE(db.find(pid) == nullptr); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; @@ -1975,7 +1975,7 @@ BOOST_AUTO_TEST_CASE( custom_operation_required_auths_after_fork ) { db.push_transaction(trx); // Now the proposal should have processed and been removed from the database - BOOST_REQUIRE_EQUAL(db.find(pid), nullptr); + BOOST_REQUIRE(db.find(pid) == nullptr); } catch (fc::exception& e) { edump((e.to_detail_string())); throw; From e4a10184fb815f20ac176fa2b15d7a28e490bf0c Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sun, 4 Aug 2019 23:07:44 -0500 Subject: [PATCH 018/534] Include hardfork.hpp in db_notify.cpp --- libraries/chain/db_notify.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 791367267d..b3e9933c6d 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -17,6 +17,7 @@ #include #include #include +#include using namespace fc; using namespace graphene::chain; From 8d3f7faced4701491ac9c36f2fa583381d7ea6e7 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Mon, 5 Aug 2019 15:54:22 +0200 Subject: [PATCH 019/534] Wrapped long lines --- libraries/chain/market_evaluator.cpp | 3 ++- tests/tests/swan_tests.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index fa6b590632..bfe9718067 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -409,7 +409,8 @@ void_result bid_collateral_evaluator::do_evaluate(const bid_collateral_operation ("oc", _bid->get_additional_collateral().amount)("nc", o.additional_collateral.amount) ("b", d.get_balance(*_paying_account, o.additional_collateral.asset_id(d)).amount) ); } else - FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= o.additional_collateral, + FC_ASSERT( d.get_balance( *_paying_account, + _bitasset_data->options.short_backing_asset(d) ) >= o.additional_collateral, "Cannot bid ${c} collateral when payer only has ${b}", ("c", o.additional_collateral.amount) ("b", d.get_balance(*_paying_account, o.additional_collateral.asset_id(d)).amount) ); } diff --git a/tests/tests/swan_tests.cpp b/tests/tests/swan_tests.cpp index c58c93238e..67cfb200cf 100644 --- a/tests/tests/swan_tests.cpp +++ b/tests/tests/swan_tests.cpp @@ -417,8 +417,10 @@ BOOST_AUTO_TEST_CASE( bid_issue_1692 ) int64_t b2_balance = get_balance( borrower2(), back() ); bid_collateral( borrower2(), back().amount(1000), swan().amount(100) ); BOOST_CHECK_EQUAL( get_balance( borrower2(), back() ), b2_balance - 1000 ); - GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance), swan().amount(200) ), fc::assert_exception ); - GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance-999), swan().amount(200) ), fc::assert_exception ); + GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance), swan().amount(200) ), + fc::assert_exception ); + GRAPHENE_REQUIRE_THROW( bid_collateral( borrower2(), back().amount(b2_balance-999), swan().amount(200) ), + fc::assert_exception ); generate_blocks( HARDFORK_CORE_1692_TIME + 30 ); From fc3e6b871d0ad101310d223594740afe8bc86275 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Mon, 5 Aug 2019 18:33:59 +0200 Subject: [PATCH 020/534] Added TODO about HF check --- libraries/chain/market_evaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/market_evaluator.cpp b/libraries/chain/market_evaluator.cpp index bfe9718067..3d38a203aa 100644 --- a/libraries/chain/market_evaluator.cpp +++ b/libraries/chain/market_evaluator.cpp @@ -401,7 +401,7 @@ void_result bid_collateral_evaluator::do_evaluate(const bid_collateral_operation if( o.additional_collateral.amount > 0 ) { - if( _bid && d.head_block_time() >= HARDFORK_CORE_1692_TIME ) + if( _bid && d.head_block_time() >= HARDFORK_CORE_1692_TIME ) // TODO: see if HF check can be removed after HF { asset delta = o.additional_collateral - _bid->get_additional_collateral(); FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= delta, From 559867c262567eb431f6a266457771294a648a32 Mon Sep 17 00:00:00 2001 From: manikey123 Date: Sun, 11 Aug 2019 18:12:11 -0700 Subject: [PATCH 021/534] BTS PR 1733 --- libraries/app/application.cpp | 55 ++++ libraries/app/database_api.cpp | 37 ++- .../app/include/graphene/app/application.hpp | 11 + tests/common/database_fixture.cpp | 114 +++++-- tests/common/database_fixture.hpp | 1 + tests/tests/database_api_tests.cpp | 304 ++++++++++++++++++ 6 files changed, 487 insertions(+), 35 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 4f835ff10d..601afc2904 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -349,6 +349,39 @@ void application_impl::set_api_limit() { if(_options->count("api-limit-list-htlcs")){ _app_options.api_limit_list_htlcs = _options->at("api-limit-list-htlcs").as(); } + if(_options->count("api-limit-lookup-accounts")) { + _app_options.api_limit_lookup_accounts = _options->at("api-limit-lookup-accounts").as(); + } + if(_options->count("api-limit-lookup-witness-accounts")) { + _app_options.api_limit_lookup_witness_accounts = _options->at("api-limit-lookup-witness-accounts").as(); + } + if(_options->count("api-limit-lookup-committee-member-accounts")) { + _app_options.api_limit_lookup_committee_member_accounts = _options->at("api-limit-lookup-committee-member-accounts").as(); + } + if(_options->count("api-limit-lookup-vote-ids")) { + _app_options.api_limit_lookup_vote_ids = _options->at("api-limit-lookup-vote-ids").as(); + } + if(_options->count("api-limit-get-account-limit-orders")) { + _app_options.api_limit_get_account_limit_orders = _options->at("api-limit-get-account-limit-orders").as(); + } + if(_options->count("api-limit-get-collateral-bids")) { + _app_options.api_limit_get_collateral_bids = _options->at("api-limit-get-collateral-bids").as(); + } + if(_options->count("api-limit-get-top-markets")) { + _app_options.api_limit_get_top_markets = _options->at("api-limit-get-top-markets").as(); + } + if(_options->count("api-limit-get-trade-history")) { + _app_options.api_limit_get_trade_history = _options->at("api-limit-get-trade-history").as(); + } + if(_options->count("api-limit-get-trade-history-by-sequence")) { + _app_options.api_limit_get_trade_history_by_sequence = _options->at("api-limit-get-trade-history-by-sequence").as(); + } + if(_options->count("api-limit-get-withdraw-permissions-by-giver")) { + _app_options.api_limit_get_withdraw_permissions_by_giver = _options->at("api-limit-get-withdraw-permissions-by-giver").as(); + } + if(_options->count("api-limit-get-withdraw-permissions-by-recipient")) { + _app_options.api_limit_get_withdraw_permissions_by_recipient = _options->at("api-limit-get-withdraw-permissions-by-recipient").as(); + } } void application_impl::startup() @@ -1044,6 +1077,28 @@ void application::set_program_options(boost::program_options::options_descriptio "For database_api_impl::get_limit_orders to set its default limit value as 300") ("api-limit-get-order-book",boost::program_options::value()->default_value(50), "For database_api_impl::get_order_book to set its default limit value as 50") + ("api-limit-lookup-accounts",boost::program_options::value()->default_value(1000), + "For database_api_impl::lookup_accounts to set its default limit values as 1000") + ("api-limit-lookup-witness-accounts",boost::program_options::value()->default_value(1000), + "For database_api_impl::lookup_witness_accounts to set its default limit values as 1000") + ("api-limit-lookup-committee-member-accounts",boost::program_options::value()->default_value(1000), + "For database_api_impl::lookup_committee_member_accounts to set its default limit values as 1000") + ("api-limit-lookup-vote-ids",boost::program_options::value()->default_value(1000), + "For database_api_impl::lookup_vote_ids to set its default limit values as 1000") + ("api-limit-get-account-limit-orders",boost::program_options::value()->default_value(101), + "For database_api_impl::get_account_limit_orders to set its default limit values as 101") + ("api-limit-get-collateral-bids",boost::program_options::value()->default_value(100), + "For database_api_impl::get_collateral_bids to set its default limit values as 100") + ("api-limit-get-top-markets",boost::program_options::value()->default_value(100), + "For database_api_impl::get_top_markets to set its default limit values as 100") + ("api-limit-get-trade-history",boost::program_options::value()->default_value(100), + "For database_api_impl::get_trade_history to set its default limit values as 100") + ("api-limit-get-trade-history-by-sequence",boost::program_options::value()->default_value(100), + "For database_api_impl::get_trade_history_by_sequence to set its default limit values as 100") + ("api-limit-get-withdraw-permissions-by-giver",boost::program_options::value()->default_value(101), + "For database_api_impl::get_withdraw_permissions_by_giver to set its default limit values as 101") + ("api-limit-get-withdraw-permissions-by-recipient",boost::program_options::value()->default_value(101), + "For database_api_impl::get_withdraw_permissions_by_recipient to set its default limit values as 101") ; command_line_options.add(configuration_file_options); command_line_options.add_options() diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index ab6889c7b3..79f668566c 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -864,7 +864,8 @@ vector database_api::get_account_limit_orders( const string& vector database_api_impl::get_account_limit_orders( const string& account_name_or_id, const string &base, const string "e, uint32_t limit, optional ostart_id, optional ostart_price) { - FC_ASSERT( limit <= 101 ); + uint64_t api_limit_get_account_limit_orders =_app_options->api_limit_get_account_limit_orders; + FC_ASSERT( limit <= api_limit_get_account_limit_orders ); vector results; uint32_t count = 0; @@ -1169,7 +1170,8 @@ map database_api::lookup_accounts(const string& lower_bo map database_api_impl::lookup_accounts(const string& lower_bound_name, uint32_t limit)const { - FC_ASSERT( limit <= 1000 ); + uint64_t api_limit_lookup_accounts = _app_options->api_limit_lookup_accounts; + FC_ASSERT( limit <= api_limit_lookup_accounts ); const auto& accounts_by_name = _db.get_index_type().indices().get(); map result; @@ -1578,7 +1580,8 @@ vector database_api::get_collateral_bids(const std::strin vector database_api_impl::get_collateral_bids(const std::string& asset, uint32_t limit, uint32_t skip)const { try { - FC_ASSERT( limit <= 100 ); + uint64_t api_limit_get_collateral_bids=_app_options->api_limit_get_collateral_bids; + FC_ASSERT( limit <= api_limit_get_collateral_bids ); const asset_id_type asset_id = get_asset_from_string(asset)->id; const asset_object& swan = asset_id(_db); FC_ASSERT( swan.is_market_issued() ); @@ -1589,7 +1592,14 @@ vector database_api_impl::get_collateral_bids(const std:: auto start = aidx.lower_bound( boost::make_tuple( asset_id, price::max(back.id, asset_id), collateral_bid_id_type() ) ); auto end = aidx.lower_bound( boost::make_tuple( asset_id, price::min(back.id, asset_id), collateral_bid_id_type(GRAPHENE_DB_MAX_INSTANCE_ID) ) ); vector result; - while( skip-- > 0 && start != end ) { ++start; } + if(skip 0) { result.push_back(*start); @@ -1746,7 +1756,7 @@ vector database_api_impl::get_top_markets(uint32_t limit)const { FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." ); - FC_ASSERT( limit <= 100 ); + FC_ASSERT( limit <= _app_options->api_limit_get_top_markets ); const auto& volume_idx = _db.get_index_type().indices().get(); auto itr = volume_idx.rbegin(); @@ -1784,7 +1794,7 @@ vector database_api_impl::get_trade_history( const string& base, { FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." ); - FC_ASSERT( limit <= 100 ); + FC_ASSERT( limit <= _app_options->api_limit_get_trade_history ); auto assets = lookup_asset_symbols( {base, quote} ); FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); @@ -1875,7 +1885,7 @@ vector database_api_impl::get_trade_history_by_sequence( { FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." ); - FC_ASSERT( limit <= 100 ); + FC_ASSERT( limit <= _app_options->api_limit_get_trade_history_by_sequence ); FC_ASSERT( start >= 0 ); int64_t start_seq = -start; @@ -2006,7 +2016,8 @@ map database_api::lookup_witness_accounts(const string& map database_api_impl::lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const { - FC_ASSERT( limit <= 1000 ); + uint64_t api_limit_lookup_witness_accounts = _app_options->api_limit_lookup_witness_accounts; + FC_ASSERT( limit <= api_limit_lookup_witness_accounts ); const auto& witnesses_by_id = _db.get_index_type().indices().get(); // we want to order witnesses by account name, but that name is in the account object @@ -2082,7 +2093,8 @@ map database_api::lookup_committee_member_acco map database_api_impl::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const { - FC_ASSERT( limit <= 1000 ); + uint64_t api_limit_lookup_committee_member_accounts = _app_options->api_limit_lookup_committee_member_accounts; + FC_ASSERT( limit <= api_limit_lookup_committee_member_accounts ); const auto& committee_members_by_id = _db.get_index_type().indices().get(); // we want to order committee_members by account name, but that name is in the account object @@ -2180,7 +2192,8 @@ vector database_api::lookup_vote_ids( const vector& votes vector database_api_impl::lookup_vote_ids( const vector& votes )const { - FC_ASSERT( votes.size() < 1000, "Only 1000 votes can be queried at a time" ); + uint64_t api_limit_lookup_vote_ids = _app_options->api_limit_lookup_vote_ids; + FC_ASSERT( votes.size() < api_limit_lookup_vote_ids, "Only 1000 votes can be queried at a time" ); const auto& witness_idx = _db.get_index_type().indices().get(); const auto& committee_idx = _db.get_index_type().indices().get(); @@ -2563,7 +2576,7 @@ vector database_api::get_withdraw_permissions_by_giv vector database_api_impl::get_withdraw_permissions_by_giver(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit)const { - FC_ASSERT( limit <= 101 ); + FC_ASSERT( limit <= _app_options->api_limit_get_withdraw_permissions_by_giver ); vector result; const auto& withdraw_idx = _db.get_index_type().indices().get(); @@ -2585,7 +2598,7 @@ vector database_api::get_withdraw_permissions_by_rec vector database_api_impl::get_withdraw_permissions_by_recipient(const std::string account_id_or_name, withdraw_permission_id_type start, uint32_t limit)const { - FC_ASSERT( limit <= 101 ); + FC_ASSERT( limit <= _app_options->api_limit_get_withdraw_permissions_by_recipient ); vector result; const auto& withdraw_idx = _db.get_index_type().indices().get(); diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 4df4cf6100..eae2929e58 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -56,6 +56,17 @@ namespace graphene { namespace app { uint64_t api_limit_get_limit_orders = 300; uint64_t api_limit_get_order_book = 50; uint64_t api_limit_list_htlcs = 100; + uint64_t api_limit_lookup_accounts = 1000; + uint64_t api_limit_lookup_witness_accounts = 1000; + uint64_t api_limit_lookup_committee_member_accounts = 1000; + uint64_t api_limit_lookup_vote_ids = 1000; + uint64_t api_limit_get_account_limit_orders = 101; + uint64_t api_limit_get_collateral_bids = 100; + uint64_t api_limit_get_top_markets = 100; + uint64_t api_limit_get_trade_history = 100; + uint64_t api_limit_get_trade_history_by_sequence = 100; + uint64_t api_limit_get_withdraw_permissions_by_giver = 101; + uint64_t api_limit_get_withdraw_permissions_by_recipient = 101; }; class application diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 1b3a5fccbf..e31eb712c2 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -133,76 +133,125 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) { options.insert(std::make_pair("max-ops-per-account", boost::program_options::variable_value((uint64_t)125, false))); options.insert(std::make_pair("api-limit-get-account-history-operations", boost::program_options::variable_value((uint64_t)300, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_account_history") { options.insert(std::make_pair("max-ops-per-account", boost::program_options::variable_value((uint64_t)125, false))); options.insert(std::make_pair("api-limit-get-account-history", boost::program_options::variable_value((uint64_t)250, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_grouped_limit_orders") { options.insert(std::make_pair("api-limit-get-grouped-limit-orders", boost::program_options::variable_value((uint64_t)250, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("grouped_orders"), false))); } if(current_test_name =="api_limit_get_relative_account_history") { options.insert(std::make_pair("max-ops-per-account", boost::program_options::variable_value((uint64_t)125, false))); options.insert(std::make_pair("api-limit-get-relative-account-history", boost::program_options::variable_value((uint64_t)250, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_account_history_by_operations") { options.insert(std::make_pair("api-limit-get-account-history-by-operations", boost::program_options::variable_value((uint64_t)250, false))); options.insert(std::make_pair("api-limit-get-relative-account-history", boost::program_options::variable_value((uint64_t)250, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_asset_holders") { options.insert(std::make_pair("api-limit-get-asset-holders", boost::program_options::variable_value((uint64_t)250, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_key_references") { options.insert(std::make_pair("api-limit-get-key-references", boost::program_options::variable_value((uint64_t)200, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value(string("account_history"), false))); } if(current_test_name =="api_limit_get_limit_orders") { options.insert(std::make_pair("api-limit-get-limit-orders", boost::program_options::variable_value( (uint64_t)350, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value( - string("account_history"), false))); } if(current_test_name =="api_limit_get_call_orders") { options.insert(std::make_pair("api-limit-get-call-orders", boost::program_options::variable_value( (uint64_t)350, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value( - string("account_history"), false))); } if(current_test_name =="api_limit_get_settle_orders") { options.insert(std::make_pair("api-limit-get-settle-orders", boost::program_options::variable_value( (uint64_t)350, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value( - string("account_history"), false))); } if(current_test_name =="api_limit_get_order_book") { options.insert(std::make_pair("api-limit-get-order-book", boost::program_options::variable_value( (uint64_t)80, false))); - options.insert(std::make_pair("plugins", boost::program_options::variable_value( - string("account_history"), false))); } if( current_test_name == "asset_in_collateral" ) { options.insert( std::make_pair( "plugins", boost::program_options::variable_value( string("api_helper_indexes"), false ) ) ); } - - // add account tracking for ahplugin for special test case with track-account enabled + if(current_test_name =="api_limit_lookup_accounts") + { + options.insert(std::make_pair("api-limit-lookup-accounts", boost::program_options::variable_value + ((uint64_t)200, false))); + } + if(current_test_name =="api_limit_lookup_witness_accounts") + { + options.insert(std::make_pair("api-limit-lookup-witness-accounts", boost::program_options::variable_value + ((uint64_t)200, false))); + } + if(current_test_name =="api_limit_lookup_committee_member_accounts") + { + options.insert(std::make_pair("api-limit-lookup-committee-member-accounts", boost::program_options::variable_value + ((uint64_t)200, false))); + } + if(current_test_name =="api_limit_lookup_committee_member_accounts") + { + options.insert(std::make_pair("api-limit-lookup-committee-member-accounts", boost::program_options::variable_value + ((uint64_t)200, false))); + } + if(current_test_name =="api_limit_lookup_vote_ids") + { + options.insert(std::make_pair("api-limit-lookup-vote-ids", boost::program_options::variable_value + ((uint64_t)3, false))); + } + if(current_test_name =="api_limit_get_account_limit_orders") + { + options.insert(std::make_pair("api-limit-get-account-limit-orders", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_collateral_bids") + { + options.insert(std::make_pair("api-limit-get-collateral-bids", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_top_markets") + { + options.insert(std::make_pair("api-limit-get-top-markets", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_trade_history") + { + options.insert(std::make_pair("api-limit-get-trade-history", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_trade_history_by_sequence") + { + options.insert(std::make_pair("api-limit-get-trade-history-by-sequence", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_withdraw_permissions_by_giver") + { + options.insert(std::make_pair("api-limit-get-withdraw-permissions-by-giver", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_withdraw_permissions_by_recipient") + { + options.insert(std::make_pair("api-limit-get-withdraw-permissions-by-recipient", boost::program_options::variable_value + ((uint64_t)250, false))); + } + if(current_test_name =="api_limit_get_full_accounts2") + { + options.insert(std::make_pair("api-limit-get-full-accounts", boost::program_options::variable_value + ((uint64_t)200, false))); + } + // add account tracking for ahplugin for special test case with track-account enabled if( !options.count("track-account") && current_test_name == "track_account") { std::vector track_account; std::string track = "\"1.2.17\""; @@ -243,12 +292,8 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) ahplugin->plugin_set_app(&app); ahplugin->plugin_initialize(options); ahplugin->plugin_startup(); - if (current_test_name == "api_limit_get_account_history_operations" || current_test_name == "api_limit_get_account_history" - || current_test_name == "api_limit_get_grouped_limit_orders" || current_test_name == "api_limit_get_relative_account_history" - || current_test_name == "api_limit_get_account_history_by_operations" || current_test_name =="api_limit_get_asset_holders" - || current_test_name =="api_limit_get_key_references" || current_test_name =="api_limit_get_limit_orders" - || current_test_name =="api_limit_get_call_orders" || current_test_name =="api_limit_get_settle_orders" - || current_test_name =="api_limit_get_order_book") + + if(validation_current_test_name_for_setting_api_limit(current_test_name)) { app.initialize(graphene::utilities::temp_directory_path(), options); app.set_api_limit(); @@ -380,7 +425,30 @@ string database_fixture::generate_anon_acct_name() // to workaround issue #46 return "anon-acct-x" + std::to_string( anon_acct_count++ ); } +bool database_fixture::validation_current_test_name_for_setting_api_limit(string & current_test_name) const +{ + vector valid_testcase {"api_limit_get_account_history_operations","api_limit_get_account_history" + ,"api_limit_get_grouped_limit_orders","api_limit_get_relative_account_history" + ,"api_limit_get_account_history_by_operations","api_limit_get_asset_holders" + ,"api_limit_get_key_references","api_limit_get_limit_orders" + ,"api_limit_get_call_orders","api_limit_get_settle_orders" + ,"api_limit_get_order_book","api_limit_lookup_accounts" + ,"api_limit_lookup_witness_accounts","api_limit_lookup_committee_member_accounts" + ,"api_limit_lookup_vote_ids","api_limit_get_account_limit_orders" + ,"api_limit_get_collateral_bids","api_limit_get_top_markets" + ,"api_limit_get_trade_history", "api_limit_get_trade_history_by_sequence" + ,"api_limit_get_withdraw_permissions_by_giver","api_limit_get_withdraw_permissions_by_recipient" + ,"api_limit_get_full_accounts2"}; + for(string i_valid_testcase: valid_testcase) + { + if(i_valid_testcase.compare(current_test_name)==0) + { + return true; + } + } + return false; +} void database_fixture::verify_asset_supplies( const database& db ) { //wlog("*** Begin asset supply verification ***"); diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 5368ce018b..7747c1c11a 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -371,6 +371,7 @@ struct database_fixture { vector< operation_history_object > get_operation_history( account_id_type account_id )const; vector< graphene::market_history::order_history_object > get_market_order_history( asset_id_type a, asset_id_type b )const; + bool validation_current_test_name_for_setting_api_limit (string & current_test_name) const; }; namespace test { diff --git a/tests/tests/database_api_tests.cpp b/tests/tests/database_api_tests.cpp index 4b1d2b6b32..22384e847e 100644 --- a/tests/tests/database_api_tests.cpp +++ b/tests/tests/database_api_tests.cpp @@ -1679,5 +1679,309 @@ BOOST_AUTO_TEST_CASE( asset_in_collateral ) BOOST_CHECK_EQUAL( 1000, assets[1].total_backing_collateral->value ); } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( api_limit_lookup_accounts ) { + try{ + graphene::app::database_api db_api( db, &( app.get_options() )); + auto bob_private_key = generate_private_key("bob"); + account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; + transfer(account_id_type(), bob_id, asset(100)); + generate_block(); + fc::usleep(fc::milliseconds(100)); + GRAPHENE_CHECK_THROW(db_api.lookup_accounts("bob",220), fc::exception); + map result =db_api.lookup_accounts("bob",190); + BOOST_REQUIRE_EQUAL( result.size(), 17u); + + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( api_limit_lookup_witness_accounts ) { + try{ + graphene::app::database_api db_api( db, &( app.get_options() )); + auto bob_private_key = generate_private_key("bob"); + account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; + transfer(account_id_type(), bob_id, asset(100)); + generate_block(); + fc::usleep(fc::milliseconds(100)); + GRAPHENE_CHECK_THROW(db_api.lookup_witness_accounts("bob",220), fc::exception); + map result =db_api.lookup_witness_accounts("bob",190); + BOOST_REQUIRE_EQUAL( result.size(), 10u); + + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE( api_limit_get_full_accounts2 ) { + + try { + graphene::app::database_api db_api(db, &(this->app.get_options())); + vector accounts; + for (int i=0; i<201; i++) { + std::string acct_name = "mytempacct" + std::to_string(i); + const account_object& account_name=create_account(acct_name); + accounts.push_back(account_name.name); + } + GRAPHENE_CHECK_THROW(db_api.get_full_accounts(accounts, false), fc::exception); + accounts.erase(accounts.begin()); + auto full_accounts = db_api.get_full_accounts(accounts, false); + BOOST_REQUIRE_EQUAL(full_accounts.size(), 200u); + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_withdraw_permissions_by_recipient){ + try{ + graphene::app::database_api db_api( db, &app.get_options()); + ACTORS((bob)) ; + withdraw_permission_id_type withdraw_permission; + transfer(account_id_type(), bob_id, asset(100)); + GRAPHENE_CHECK_THROW(db_api.get_withdraw_permissions_by_recipient( + "bob",withdraw_permission, 251), fc::exception); + vector result =db_api.get_withdraw_permissions_by_recipient( + "bob",withdraw_permission,250); + BOOST_REQUIRE_EQUAL( result.size(), 0u); + }catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_withdraw_permissions_by_giver){ + try{ + graphene::app::database_api db_api( db, &app.get_options()); + ACTORS((bob)) ; + withdraw_permission_id_type withdraw_permission; + transfer(account_id_type(), bob_id, asset(100)); + GRAPHENE_CHECK_THROW(db_api.get_withdraw_permissions_by_giver( + "bob",withdraw_permission, 251), fc::exception); + vector result =db_api.get_withdraw_permissions_by_giver( + "bob",withdraw_permission,250); + BOOST_REQUIRE_EQUAL( result.size(), 0u); + }catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_trade_history_by_sequence){ + try{ + app.enable_plugin("market_history"); + graphene::app::application_options opt=app.get_options(); + opt.has_market_history_plugin = true; + graphene::app::database_api db_api( db, &opt); + ACTORS((bob) (alice) (fred)) ; + const auto& bitusd = create_bitasset("USDBIT", bob_id); + asset_id_type asset_1, asset_2; + asset_1 = bitusd.id; + asset_2 = asset_id_type(); + GRAPHENE_CHECK_THROW(db_api.get_trade_history_by_sequence( + std::string( static_cast(asset_1)), + std::string( static_cast(asset_2)), + 0,fc::time_point_sec(1532008940), 251), fc::exception); + vector result =db_api.get_trade_history_by_sequence( + std::string( static_cast(asset_1)), + std::string( static_cast(asset_2)), + 0,fc::time_point_sec(1532008940),250); + BOOST_REQUIRE_EQUAL( result.size(), 0u); + }catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(api_limit_get_trade_history){ + try{ + app.enable_plugin("market_history"); + graphene::app::application_options opt=app.get_options(); + opt.has_market_history_plugin = true; + graphene::app::database_api db_api( db, &opt); + ACTORS((bob) (alice) (fred)) ; + const auto& bitusd = create_bitasset("USDBIT", bob_id); + asset_id_type asset_1, asset_2; + asset_1 = bitusd.id; + asset_2 = asset_id_type(); + GRAPHENE_CHECK_THROW(db_api.get_trade_history( + std::string( static_cast(asset_1)), + std::string( static_cast(asset_2)), + fc::time_point_sec(1532008920),fc::time_point_sec(1532008940), + 251), fc::exception); + vector result =db_api.get_trade_history( + std::string( static_cast(asset_1)), + std::string( static_cast(asset_2)), + fc::time_point_sec(1532008920),fc::time_point_sec(1532008940),250); + BOOST_REQUIRE_EQUAL( result.size(), 0u); + }catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_top_markets){ + try{ + app.enable_plugin("market_history"); + graphene::app::application_options opt=app.get_options(); + opt.has_market_history_plugin = true; + graphene::app::database_api db_api( db, &opt); + ACTORS((bob) (alice) (fred)) ; + const auto& bitusd = create_bitasset("USDBIT", bob_id); + asset_id_type asset_1, asset_2; + asset_1 = bitusd.id; + asset_2 = asset_id_type(); + GRAPHENE_CHECK_THROW(db_api.get_top_markets(251), fc::exception); + vector result =db_api.get_top_markets(250); + BOOST_REQUIRE_EQUAL( result.size(), 0u); + }catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_collateral_bids) { + try { + graphene::app::database_api db_api( db, &( app.get_options() )); + + int64_t init_balance = 10000; + ///account_id_type borrower, borrower2, feedproducer; + asset_id_type swan, back; + ACTORS((borrower) (borrower2) (feedproducer)) ; + const auto& bitusd = create_bitasset("USDBIT", feedproducer_id); + swan = bitusd.id; + back = asset_id_type(); + update_feed_producers(swan(db), {feedproducer_id}); + transfer(committee_account, borrower_id, asset(init_balance)); + transfer(committee_account, borrower2_id, asset(init_balance)); + + generate_blocks( HARDFORK_CORE_216_TIME ); + generate_block(); + + price_feed feed; + feed.maintenance_collateral_ratio = 1750; // need to set this explicitly, testnet has a different default + feed.settlement_price = swan(db).amount(1) / back(db).amount(1); + publish_feed(swan(db), feedproducer_id(db), feed); + // start out with 2:1 collateral + borrow(borrower_id(db), swan(db).amount(10), back(db).amount(2*10)); + borrow(borrower2_id(db), swan(db).amount(10), back(db).amount(4*10)); + //feed 1: 2 + feed.settlement_price = swan(db).amount(1) / back(db).amount(2); + publish_feed(swan(db), feedproducer_id(db), feed); + + // this sell order is designed to trigger a black swan + + create_sell_order( borrower2_id(db), swan(db).amount(1), back(db).amount(3) )->id; + BOOST_CHECK( swan(db).bitasset_data(db).has_settlement() ); + //making 3 collateral bids + for (int i=0; i<3; i++) { + + std::string acct_name = "mytempacct" + std::to_string(i); + account_id_type account_id=create_account(acct_name).id; + transfer(committee_account, account_id, asset(init_balance)); + bid_collateral(account_id(db), back(db).amount(10), swan(db).amount(1)); + } + auto swan_symbol = swan(db).symbol; + + + //validating normal case; total_bids =3 ; result_bids=3 + vector result_bids = db_api.get_collateral_bids(swan_symbol, 250, 0); + BOOST_CHECK_EQUAL( 3u, result_bids.size() ); + + //verify skip /// inefficient code test + //skip < total_bids; skip=1; total_bids =3 ; result_bids=2 + result_bids = db_api.get_collateral_bids(swan_symbol, 250, 1); + BOOST_CHECK_EQUAL( 2u, result_bids.size() ); + //skip= total_bids; skip=3; total_bids =3 ; result_bids=0 + result_bids = db_api.get_collateral_bids(swan_symbol, 250, 3); + BOOST_CHECK_EQUAL( 0u, result_bids.size() ); + //skip> total_bids; skip=4; total_bids =3 ; result_bids=0 + result_bids = db_api.get_collateral_bids(swan_symbol, 250, 4); + BOOST_CHECK_EQUAL( 0u, result_bids.size() ); + + //verify limit // inefficient code test + //limit= api_limit + for (int i=3; i<255; i++) { + std::string acct_name = "mytempacct" + std::to_string(i); + account_id_type account_id=create_account(acct_name).id; + transfer(committee_account, account_id, asset(init_balance)); + bid_collateral(account_id(db), back(db).amount(10), swan(db).amount(1)); + } + result_bids=db_api.get_collateral_bids(swan_symbol, 250, 0); + BOOST_CHECK_EQUAL( 250u, result_bids.size() ); + //limit> api_limit throw error + GRAPHENE_CHECK_THROW(db_api.get_collateral_bids(swan_symbol, 253, 3), fc::exception); + + } + catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE(api_limit_get_account_limit_orders) { + try { + + ACTORS((seller)); + const auto &bitcny = create_bitasset("CNY"); + const auto &core = asset_id_type()(db); + int64_t init_balance(10000000); + transfer(committee_account, seller_id, asset(init_balance)); + + /// Create versatile orders + for (size_t i = 0; i < 250; ++i) { + BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250+i))); + } + + graphene::app::database_api db_api( db, &( app.get_options() )); + std::vector results=db_api.get_account_limit_orders(seller.name, GRAPHENE_SYMBOL, "CNY",250); + BOOST_REQUIRE_EQUAL( results.size(), 250u); + GRAPHENE_CHECK_THROW( db_api.get_account_limit_orders(seller.name, GRAPHENE_SYMBOL, "CNY",251), fc::exception); + + } + catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_CASE( api_limit_lookup_vote_ids ) { + try{ + graphene::app::database_api db_api( db, &( app.get_options() )); + ACTORS( (connie)(whitney)(wolverine) ); + fund(connie); + upgrade_to_lifetime_member(connie); + fund(whitney); + upgrade_to_lifetime_member(whitney); + fund(wolverine); + upgrade_to_lifetime_member(wolverine); + const auto& committee = create_committee_member( connie ); + const auto& witness = create_witness( whitney ); + const auto& worker = create_worker( wolverine_id ); + std::vector votes; + votes.push_back( committee.vote_id ); + votes.push_back( witness.vote_id ); + const auto results = db_api.lookup_vote_ids( votes ); + BOOST_REQUIRE_EQUAL( results.size(), 2u); + votes.push_back( worker.vote_for ); + GRAPHENE_CHECK_THROW(db_api.lookup_vote_ids(votes), fc::exception); + + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE( api_limit_lookup_committee_member_accounts ) { + try{ + graphene::app::database_api db_api( db, &( app.get_options() )); + auto bob_private_key = generate_private_key("bob"); + account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; + transfer(account_id_type(), bob_id, asset(100)); + generate_block(); + fc::usleep(fc::milliseconds(100)); + GRAPHENE_CHECK_THROW(db_api.lookup_committee_member_accounts("bob",220), fc::exception); + std::map result =db_api.lookup_committee_member_accounts("bob",190); + BOOST_REQUIRE_EQUAL( result.size(), 10u); + + } catch (fc::exception& e) { + edump((e.to_detail_string())); + throw; + } +} BOOST_AUTO_TEST_SUITE_END() From 14adefc6d1b860267c76eb246b6ed5b9fafc9b61 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Fri, 16 Aug 2019 14:21:15 +0200 Subject: [PATCH 022/534] Added flag to pre-generate hardfork.hpp instead of using cat-parts --- CMakeLists.txt | 3 +++ libraries/chain/CMakeLists.txt | 21 ++++++++++++++++----- programs/build_helpers/CMakeLists.txt | 15 ++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd9db30bf5..fbc287f29f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,9 @@ set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" ) set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) +SET( GRAPHENE_PREGENERATE_FILES OFF CACHE BOOL + "ON for pre-creating generated sources instead of during the build. Useful for cross-compilation." ) + if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) set( CMAKE_CXX_EXTENSIONS ON ) # for __int128 support else( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index fbcd6ab866..04905c6b66 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -1,10 +1,6 @@ -add_custom_target( build_hardfork_hpp - COMMAND cat-parts "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d" "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) set_source_files_properties( "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" PROPERTIES GENERATED TRUE ) -add_dependencies( build_hardfork_hpp cat-parts ) - file(GLOB HEADERS "include/graphene/chain/*.hpp") if( GRAPHENE_DISABLE_UNITY_BUILD ) @@ -73,7 +69,22 @@ add_library( graphene_chain "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) -add_dependencies( graphene_chain build_hardfork_hpp ) +if( GRAPHENE_PREGENERATE_FILES ) + message( STATUS "Generating hardfork.hpp" ) + file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/" ) + file( REMOVE "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) + file( GLOB HARDFORKS "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d/*" ) + foreach( HF ${HARDFORKS} ) + file( READ "${HF}" INCL ) + file( APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" "${INCL}" ) + endforeach( HF ) +else( GRAPHENE_PREGENERATE_FILES ) + add_custom_target( build_hardfork_hpp + COMMAND cat-parts "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d" "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) + add_dependencies( build_hardfork_hpp cat-parts ) + add_dependencies( graphene_chain build_hardfork_hpp ) +endif( GRAPHENE_PREGENERATE_FILES ) + target_link_libraries( graphene_chain fc graphene_db graphene_protocol ) target_include_directories( graphene_chain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" ) diff --git a/programs/build_helpers/CMakeLists.txt b/programs/build_helpers/CMakeLists.txt index 7a625b258c..4ab1240e50 100644 --- a/programs/build_helpers/CMakeLists.txt +++ b/programs/build_helpers/CMakeLists.txt @@ -1,11 +1,12 @@ -add_executable( cat-parts cat-parts.cpp ) -if( UNIX AND NOT APPLE ) - set(rt_library rt ) -endif() - -# we only actually need Boost, but link against FC for now so we don't duplicate it. -target_link_libraries( cat-parts PRIVATE fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +if( NOT(GRAPHENE_PREGENERATE_FILES) ) + add_executable( cat-parts cat-parts.cpp ) + if( UNIX AND NOT APPLE ) + set(rt_library rt ) + endif() + # we only actually need Boost, but link against FC for now so we don't duplicate it. + target_link_libraries( cat-parts PRIVATE fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) +endif( NOT(GRAPHENE_PREGENERATE_FILES) ) add_executable( member_enumerator member_enumerator.cpp ) if( UNIX AND NOT APPLE ) From 476ada2c2e5596ff4eb06ba915b3222e4c296e94 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Fri, 16 Aug 2019 15:02:43 +0200 Subject: [PATCH 023/534] Pre-generate embedded genesis as well --- libraries/egenesis/CMakeLists.txt | 79 +++++++++++++++++++------------ 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/libraries/egenesis/CMakeLists.txt b/libraries/egenesis/CMakeLists.txt index 68de4b0079..4eb259af90 100644 --- a/libraries/egenesis/CMakeLists.txt +++ b/libraries/egenesis/CMakeLists.txt @@ -1,57 +1,78 @@ -add_library( graphene_egenesis_none - egenesis_none.cpp - include/graphene/egenesis/egenesis.hpp - ) +if( GRAPHENE_PREGENERATE_FILES ) + message( STATUS "Generating egenesis" ) + file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) -target_link_libraries( graphene_egenesis_none graphene_chain fc ) -target_include_directories( graphene_egenesis_none - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) - -add_executable( embed_genesis - embed_genesis.cpp - ) + if( GRAPHENE_EGENESIS_JSON ) + set( embed_genesis_args "${GRAPHENE_EGENESIS_JSON}" ) + else( GRAPHENE_EGENESIS_JSON ) + set( embed_genesis_args "genesis.json" ) + endif( GRAPHENE_EGENESIS_JSON ) + file( SHA256 "${embed_genesis_args}" chain_id ) + set( generated_file_banner "/*** GENERATED FILE - DO NOT EDIT! ***/" ) + set( genesis_json_hash "${chain_id}" ) + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" ) -target_link_libraries( embed_genesis graphene_chain graphene_app graphene_egenesis_none fc ) + file( READ "${embed_genesis_args}" genesis_json ) + string( LENGTH "${genesis_json}" genesis_json_length ) + string( REPLACE "\"" "\\\"" genesis_json_escaped "${genesis_json}" ) + set( genesis_json_array "\"${genesis_json_escaped}\"" ) + set( genesis_json_array_height 1 ) + set( genesis_json_array_width ${genesis_json_length} ) + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) -set( embed_genesis_args - -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" - -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" - ) +else( GRAPHENE_PREGENERATE_FILES ) + add_executable( embed_genesis embed_genesis.cpp ) + target_link_libraries( embed_genesis graphene_chain graphene_app graphene_egenesis_none fc ) + set( embed_genesis_args + -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" + -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" + ) -MESSAGE( STATUS "egenesis: " ${GRAPHENE_EGENESIS_JSON} ) + MESSAGE( STATUS "egenesis: " ${GRAPHENE_EGENESIS_JSON} ) -if( GRAPHENE_EGENESIS_JSON ) - list( APPEND embed_genesis_args --genesis-json "${GRAPHENE_EGENESIS_JSON}" ) -endif( GRAPHENE_EGENESIS_JSON ) + if( GRAPHENE_EGENESIS_JSON ) + list( APPEND embed_genesis_args --genesis-json "${GRAPHENE_EGENESIS_JSON}" ) + endif( GRAPHENE_EGENESIS_JSON ) -MESSAGE( STATUS "embed_genesis_args: " ${embed_genesis_args} ) + MESSAGE( STATUS "embed_genesis_args: " ${embed_genesis_args} ) -add_custom_command( - OUTPUT + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND embed_genesis ${embed_genesis_args} - DEPENDS + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND embed_genesis ${embed_genesis_args} + DEPENDS "${GRAPHENE_EGENESIS_JSON}" "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" embed_genesis ) -add_library( graphene_egenesis_brief "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" include/graphene/egenesis/egenesis.hpp ) -add_library( graphene_egenesis_full "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" include/graphene/egenesis/egenesis.hpp ) +endif( GRAPHENE_PREGENERATE_FILES ) +add_library( graphene_egenesis_none egenesis_none.cpp + include/graphene/egenesis/egenesis.hpp ) +add_library( graphene_egenesis_brief "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" + include/graphene/egenesis/egenesis.hpp ) +add_library( graphene_egenesis_full "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" + include/graphene/egenesis/egenesis.hpp ) + +target_link_libraries( graphene_egenesis_none graphene_chain fc ) target_link_libraries( graphene_egenesis_brief graphene_chain fc ) target_link_libraries( graphene_egenesis_full graphene_chain fc ) +target_include_directories( graphene_egenesis_none + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) target_include_directories( graphene_egenesis_brief PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) target_include_directories( graphene_egenesis_full PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) INSTALL( TARGETS - embed_genesis graphene_egenesis_none graphene_egenesis_brief graphene_egenesis_full + graphene_egenesis_none graphene_egenesis_brief graphene_egenesis_full RUNTIME DESTINATION bin LIBRARY DESTINATION lib From 2d73685da93ae9cd9cc6563a906c8c5a22a47006 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Fri, 16 Aug 2019 15:31:53 +0200 Subject: [PATCH 024/534] Add more escapes to genesis (for testnet mostly) --- libraries/egenesis/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/egenesis/CMakeLists.txt b/libraries/egenesis/CMakeLists.txt index 4eb259af90..c2d03407d4 100644 --- a/libraries/egenesis/CMakeLists.txt +++ b/libraries/egenesis/CMakeLists.txt @@ -16,7 +16,9 @@ if( GRAPHENE_PREGENERATE_FILES ) file( READ "${embed_genesis_args}" genesis_json ) string( LENGTH "${genesis_json}" genesis_json_length ) - string( REPLACE "\"" "\\\"" genesis_json_escaped "${genesis_json}" ) + string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) + string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) + string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) set( genesis_json_array "\"${genesis_json_escaped}\"" ) set( genesis_json_array_height 1 ) set( genesis_json_array_width ${genesis_json_length} ) From f1518aa5e4be2e8c80bfa48228e86460a559d641 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 16 Aug 2019 13:33:30 -0300 Subject: [PATCH 025/534] implement custom operations plugin --- libraries/app/CMakeLists.txt | 2 +- libraries/app/api.cpp | 64 +++ libraries/app/include/graphene/app/api.hpp | 70 ++- libraries/plugins/CMakeLists.txt | 1 + .../plugins/custom_operations/CMakeLists.txt | 25 + .../custom_operations/custom_evaluators.cpp | 117 +++++ .../custom_operations/custom_operations.cpp | 53 ++ .../custom_operations_plugin.cpp | 129 +++++ .../custom_operations/custom_evaluators.hpp | 44 ++ .../custom_operations/custom_objects.hpp | 137 +++++ .../custom_operations/custom_operations.hpp | 103 ++++ .../custom_operations_plugin.hpp | 91 ++++ .../wallet/include/graphene/wallet/wallet.hpp | 71 +++ libraries/wallet/wallet.cpp | 129 ++++- programs/witness_node/CMakeLists.txt | 2 +- programs/witness_node/main.cpp | 2 + tests/CMakeLists.txt | 15 +- tests/cli/main.cpp | 127 ++++- tests/common/database_fixture.cpp | 8 + tests/custom_operations/main.cpp | 469 ++++++++++++++++++ 20 files changed, 1652 insertions(+), 7 deletions(-) create mode 100644 libraries/plugins/custom_operations/CMakeLists.txt create mode 100644 libraries/plugins/custom_operations/custom_evaluators.cpp create mode 100644 libraries/plugins/custom_operations/custom_operations.cpp create mode 100644 libraries/plugins/custom_operations/custom_operations_plugin.cpp create mode 100644 libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp create mode 100644 libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp create mode 100644 libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp create mode 100644 libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp create mode 100644 tests/custom_operations/main.cpp diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index 71762b1d90..43a2a55254 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -16,7 +16,7 @@ add_library( graphene_app # need to link graphene_debug_witness because plugins aren't sufficiently isolated #246 target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_elasticsearch graphene_grouped_orders - graphene_api_helper_indexes + graphene_api_helper_indexes graphene_custom_operations graphene_chain fc graphene_db graphene_net graphene_utilities graphene_debug_witness ) target_include_directories( graphene_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 2dc7d2eeb6..a6aa07f126 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -48,6 +48,7 @@ template class fc::api; template class fc::api; template class fc::api; template class fc::api; +template class fc::api; template class fc::api; template class fc::api; @@ -119,6 +120,11 @@ namespace graphene { namespace app { { _orders_api = std::make_shared< orders_api >( std::ref( _app ) ); } + else if( api_name == "custom_operations_api" ) + { + if( _app.get_plugin( "custom_operations" ) ) + _custom_operations_api = std::make_shared< custom_operations_api >( std::ref( _app ) ); + } else if( api_name == "debug_api" ) { // can only enable this API if the plugin was loaded @@ -296,6 +302,12 @@ namespace graphene { namespace app { return *_debug_api; } + fc::api login_api::custom() const + { + FC_ASSERT(_custom_operations_api); + return *_custom_operations_api; + } + vector history_api::get_fill_order_history( std::string asset_a, std::string asset_b, uint32_t limit )const { FC_ASSERT(_app.chain_database()); @@ -674,4 +686,56 @@ namespace graphene { namespace app { return result; } + // custom operations api + optional custom_operations_api::get_contact_info(std::string account_id_or_name)const + { + const auto account_id = database_api.get_account_id_from_string(account_id_or_name); + auto &index = _app.chain_database()->get_index_type().indices().get(); + auto itr = index.find(account_id); + if(itr != index.end()) + return *itr; + return optional(); + } + + vector custom_operations_api::get_account_htlc_offers(std::string account_id_or_name, + htlc_order_id_type start, uint32_t limit)const + { + FC_ASSERT(limit <= 101); + + const auto account_id = database_api.get_account_id_from_string(account_id_or_name); + vector results; + auto &index = _app.chain_database()->get_index_type().indices().get(); + + auto itr = index.lower_bound(boost::make_tuple(account_id, start)); + while(itr != index.end() && itr->bitshares_account == account_id && results.size() < limit) + { + results.push_back(*itr); + ++itr; + } + return results; + } + vector custom_operations_api::get_active_htlc_offers(htlc_order_id_type start, uint32_t limit)const + { + FC_ASSERT(limit <= 101); + + vector results; + auto db = _app.chain_database(); + auto &index = db->get_index_type().indices().get(); + auto itr = index.lower_bound(make_tuple(true, db->head_block_time(), start)); + while(itr != index.end() && itr->active && itr->expiration > db->head_block_time() && results.size() < limit) + { + results.push_back(*itr); + ++itr; + } + return results; + } + optional custom_operations_api::get_htlc_offer(htlc_order_id_type id)const + { + auto &index = _app.chain_database()->get_index_type().indices().get(); + auto itr = index.find(id); + if(itr != index.end()) + return *itr; + return optional(); + } + } } // graphene::app diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index e62c19a5de..f58582da4f 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -29,8 +29,8 @@ #include #include - #include +#include #include @@ -54,6 +54,8 @@ namespace graphene { namespace app { using namespace graphene::chain; using namespace graphene::market_history; using namespace graphene::grouped_orders; + using namespace graphene::custom_operations; + using namespace fc::ecc; using std::string; using std::vector; @@ -518,6 +520,61 @@ namespace graphene { namespace app { application& _app; graphene::app::database_api database_api; }; + + /** + * @brief The custom_operations_api class exposes access to standard custom objects parsed by the + * custom_operations_plugin. + */ + class custom_operations_api + { + public: + custom_operations_api(application& app):_app(app), database_api( std::ref(*app.chain_database()), + &(app.get_options()) ){} + + /** + * @breif Get contact information of an account + * + * @param account Account name to get info from + * + * @return The contact information of the account or empty + */ + optional get_contact_info(std::string account)const; + + /** + * @breif Get htlc offers from an account + * + * @param account Account name to get htlc offers from + * @param start ID of the most recent htlc offer to retrieve + * @param limit Maximum number of order objects to retrieve + * + * @return A vector of htlc offer objects from the account + */ + vector get_account_htlc_offers(std::string account, htlc_order_id_type start, + uint32_t limit)const; + + /** + * @breif Get all active and non expired htlc offers + * + * @param start ID of the most recent htlc offer to retrieve + * @param limit Maximum number of order objects to retrieve + * + * @return A vector of active and non expired htlc offers + */ + vector get_active_htlc_offers(htlc_order_id_type start, uint32_t limit)const; + + /** + * @breif Get htlc order offer by id + * + * @param id ID of the htlc order offer to retrieve + * + * @return A vector of active and non expired htlc offers + */ + optional get_htlc_offer(htlc_order_id_type id)const; + + private: + application& _app; + graphene::app::database_api database_api; + }; } } // graphene::app extern template class fc::api; @@ -528,6 +585,7 @@ extern template class fc::api; extern template class fc::api; extern template class fc::api; extern template class fc::api; +extern template class fc::api; namespace graphene { namespace app { /** @@ -569,6 +627,8 @@ namespace graphene { namespace app { fc::api orders()const; /// @brief Retrieve the debug API (if available) fc::api debug()const; + /// @brief Retrieve the custom operations API + fc::api custom()const; /// @brief Called to enable an API, not reflected. void enable_api( const string& api_name ); @@ -584,6 +644,7 @@ namespace graphene { namespace app { optional< fc::api > _asset_api; optional< fc::api > _orders_api; optional< fc::api > _debug_api; + optional< fc::api > _custom_operations_api; }; }} // graphene::app @@ -650,6 +711,12 @@ FC_API(graphene::app::orders_api, (get_tracked_groups) (get_grouped_limit_orders) ) +FC_API(graphene::app::custom_operations_api, + (get_contact_info) + (get_account_htlc_offers) + (get_active_htlc_offers) + (get_htlc_offer) + ) FC_API(graphene::app::login_api, (login) (block) @@ -661,4 +728,5 @@ FC_API(graphene::app::login_api, (asset) (orders) (debug) + (custom) ) diff --git a/libraries/plugins/CMakeLists.txt b/libraries/plugins/CMakeLists.txt index 412b185e08..25dfab19ed 100644 --- a/libraries/plugins/CMakeLists.txt +++ b/libraries/plugins/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory( debug_witness ) add_subdirectory( snapshot ) add_subdirectory( es_objects ) add_subdirectory( api_helper_indexes ) +add_subdirectory( custom_operations ) diff --git a/libraries/plugins/custom_operations/CMakeLists.txt b/libraries/plugins/custom_operations/CMakeLists.txt new file mode 100644 index 0000000000..4202f740c8 --- /dev/null +++ b/libraries/plugins/custom_operations/CMakeLists.txt @@ -0,0 +1,25 @@ +file(GLOB HEADERS "include/graphene/custom_operations/*.hpp") + +add_library( graphene_custom_operations + custom_operations_plugin.cpp + custom_operations.cpp + custom_evaluators.cpp + ) + +target_link_libraries( graphene_custom_operations graphene_chain graphene_app ) +target_include_directories( graphene_custom_operations + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +if(MSVC) + set_source_files_properties(custom_operations_plugin.cpp custom_operations.cpp custom_evaluators.cpp + PROPERTIES COMPILE_FLAGS "/bigobj" ) +endif(MSVC) + +install( TARGETS + graphene_custom_operations + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/custom_operations" ) diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp new file mode 100644 index 0000000000..1ce465c298 --- /dev/null +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include +#include +#include + +namespace graphene { namespace custom_operations { + +custom_generic_evaluator::custom_generic_evaluator(database& db, const account_id_type account) +{ + _db = &db; + _account = account; +} + +object_id_type custom_generic_evaluator::do_apply(const account_contact_operation& op) +{ + auto &index = _db->get_index_type().indices().get(); + + auto itr = index.find(_account); + if( itr != index.end() ) + { + _db->modify( *itr, [&op, this]( account_contact_object& aco ){ + aco.account = _account; + if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; + if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; + if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; + if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; + if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; + if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; + }); + return itr->id; + } + else + { + auto created = _db->create( [&op, this]( account_contact_object& aco ) { + aco.account = _account; + if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; + if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; + if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; + if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; + if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; + if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; + }); + return created.id; + } +} + +object_id_type custom_generic_evaluator::do_apply(const create_htlc_order_operation& op) +{ + FC_ASSERT(*op.extensions.value.expiration > _db->head_block_time() + fc::seconds(3600)); + + auto order_time = _db->head_block_time(); + auto created = _db->create( [&op, &order_time, this]( htlc_order_object& hoo ) { + hoo.bitshares_account = _account; + if(op.extensions.value.bitshares_amount.valid()) hoo.bitshares_amount = *op.extensions.value.bitshares_amount; + if(op.extensions.value.blockchain.valid()) hoo.blockchain = *op.extensions.value.blockchain; + if(op.extensions.value.blockchain_account.valid()) hoo.blockchain_account = *op.extensions.value.blockchain_account; + if(op.extensions.value.blockchain_asset.valid()) hoo.blockchain_asset = *op.extensions.value.blockchain_asset; + if(op.extensions.value.blockchain_asset_precision.valid()) hoo.blockchain_asset_precision = + *op.extensions.value.blockchain_asset_precision; + if(op.extensions.value.blockchain_amount.valid()) hoo.blockchain_amount = *op.extensions.value.blockchain_amount; + if(op.extensions.value.expiration.valid()) hoo.expiration = *op.extensions.value.expiration; + if(op.extensions.value.token_contract.valid()) hoo.token_contract = *op.extensions.value.token_contract; + if(op.extensions.value.tag.valid()) hoo.tag = *op.extensions.value.tag; + + hoo.order_time = order_time; + hoo.active = true; + }); + return created.id; +} + +object_id_type custom_generic_evaluator::do_apply(const take_htlc_order_operation& op) +{ + auto &index = _db->get_index_type().indices().get(); + htlc_order_id_type htlc_order_id; + + if(op.extensions.value.htlc_order_id.valid()) { + htlc_order_id = *op.extensions.value.htlc_order_id; + auto itr = index.find(htlc_order_id); + if (itr != index.end()) { + auto close_time = _db->head_block_time(); + _db->modify(*itr, [&op, &close_time, this](htlc_order_object &hoo) { + hoo.active = false; + hoo.taker_bitshares_account = _account; + if (op.extensions.value.blockchain_account.valid()) + hoo.taker_blockchain_account = op.extensions.value.blockchain_account; + hoo.close_time = close_time; + }); + } + } + return htlc_order_id; +} + +} } diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp new file mode 100644 index 0000000000..673cb82d3b --- /dev/null +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +namespace graphene { namespace custom_operations { + +void account_contact_operation::validate()const +{ +} + +void create_htlc_order_operation::validate()const +{ + FC_ASSERT(extensions.value.bitshares_amount.valid()); + FC_ASSERT(extensions.value.bitshares_amount->amount.value > 0); + FC_ASSERT(extensions.value.blockchain.valid()); + FC_ASSERT(extensions.value.blockchain_account.valid()); + FC_ASSERT(extensions.value.blockchain_asset.valid()); + FC_ASSERT(extensions.value.blockchain_amount.valid()); + FC_ASSERT(extensions.value.expiration.valid()); +} + +void take_htlc_order_operation::validate()const +{ + FC_ASSERT(extensions.value.blockchain_account.valid()); + FC_ASSERT(extensions.value.htlc_order_id.valid()); +} + +} } //graphene::custom_operations + +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) diff --git a/libraries/plugins/custom_operations/custom_operations_plugin.cpp b/libraries/plugins/custom_operations/custom_operations_plugin.cpp new file mode 100644 index 0000000000..a8162d928d --- /dev/null +++ b/libraries/plugins/custom_operations/custom_operations_plugin.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include +#include +#include + +namespace graphene { namespace custom_operations { + +namespace detail +{ +class custom_operations_plugin_impl +{ + public: + custom_operations_plugin_impl(custom_operations_plugin& _plugin) + : _self( _plugin ) + { } + virtual ~custom_operations_plugin_impl(); + + void onBlock( const signed_block& b ); + + graphene::chain::database& database() + { + return _self.database(); + } + + custom_operations_plugin& _self; + + private: + +}; + +void custom_operations_plugin_impl::onBlock( const signed_block& b ) +{ + graphene::chain::database& db = database(); + const vector >& hist = db.get_applied_operations(); + for( const optional< operation_history_object >& o_operation : hist ) + { + if(!o_operation.valid() || !o_operation->op.is_type()) + continue; + + const custom_operation& custom_op = o_operation->op.get(); + + if(custom_op.data.size() == 0 || uint8_t(custom_op.data.data()[0]) != 0xFF) + continue; + + try { + auto unpacked = fc::raw::unpack(custom_op.data); + custom_op_visitor vtor(db, custom_op.fee_payer()); + unpacked.op.visit(vtor); + } + catch (fc::exception e) { // only api node will know if the unpack, validate or apply fails + wlog("Error: ${ex} in operation: ${op}", ("ex", e.to_detail_string())("op", fc::json::to_string(custom_op))); + continue; + } + } +} + +custom_operations_plugin_impl::~custom_operations_plugin_impl() +{ + return; +} + +} // end namespace detail + +custom_operations_plugin::custom_operations_plugin() : + my( new detail::custom_operations_plugin_impl(*this) ) +{ +} + +custom_operations_plugin::~custom_operations_plugin() +{ +} + +std::string custom_operations_plugin::plugin_name()const +{ + return "custom_operations"; +} +std::string custom_operations_plugin::plugin_description()const +{ + return "custom_operations description"; +} + +void custom_operations_plugin::plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg + ) +{ +} + +void custom_operations_plugin::plugin_initialize(const boost::program_options::variables_map& options) +{ + database().add_index< primary_index< account_contact_index > >(); + database().add_index< primary_index< htlc_orderbook_index > >(); + + database().applied_block.connect( [this]( const signed_block& b) { + my->onBlock(b); + } ); +} + +void custom_operations_plugin::plugin_startup() +{ + ilog("custom_operations: plugin_startup() begin"); +} + +} } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp new file mode 100644 index 0000000000..926df77eb8 --- /dev/null +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include +#include + +namespace graphene { namespace custom_operations { + +class custom_generic_evaluator +{ + public: + database* _db; + account_id_type _account; + custom_generic_evaluator(database& db, const account_id_type account); + + object_id_type do_apply(const account_contact_operation& o); + object_id_type do_apply(const create_htlc_order_operation& o); + object_id_type do_apply(const take_htlc_order_operation& o); +}; + +} } + +FC_REFLECT_TYPENAME( graphene::custom_operations::custom_generic_evaluator ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp new file mode 100644 index 0000000000..602a18f1c2 --- /dev/null +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include +#include + +namespace graphene { namespace custom_operations { + +using namespace chain; + +#ifndef CUSTOM_OPERATIONS_SPACE_ID +#define CUSTOM_OPERATIONS_SPACE_ID 7 +#endif + +enum types { + account_contact = 0, + create_htlc = 1, + take_htlc = 2 +}; +enum blockchains { + eos = 0, + bitcoin = 1, + ripple = 2, + ethereum = 3 +}; + +struct account_contact_object : public abstract_object +{ + static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; + static const uint8_t type_id = account_contact; + + account_id_type account; + optional name; + optional email; + optional phone; + optional address; + optional company; + optional url; +}; + +struct htlc_order_object : public abstract_object +{ + static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; + static const uint8_t type_id = create_htlc; + + account_id_type bitshares_account; + asset bitshares_amount; + blockchains blockchain; + string blockchain_account; + string blockchain_asset; + string blockchain_amount; + fc::time_point_sec expiration; + fc::time_point_sec order_time; + bool active; + + optional blockchain_asset_precision; + optional token_contract; + optional tag; + optional taker_bitshares_account; + optional taker_blockchain_account; + optional close_time; +}; + +struct by_custom_id; +struct by_custom_account; +typedef multi_index_container< + account_contact_object, + indexed_by< + ordered_non_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + member< account_contact_object, account_id_type, &account_contact_object::account > > + > +> account_contact_multi_index_type; + +typedef generic_index account_contact_index; + +struct by_bitshares_account; +struct by_active; +typedef multi_index_container< + htlc_order_object, + indexed_by< + ordered_non_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + composite_key< htlc_order_object, + member< htlc_order_object, account_id_type, &htlc_order_object::bitshares_account >, + member< object, object_id_type, &object::id > + > + >, + ordered_unique< tag, + composite_key< htlc_order_object, + member< htlc_order_object, bool, &htlc_order_object::active >, + member< htlc_order_object, fc::time_point_sec, &htlc_order_object::expiration >, + member< object, object_id_type, &object::id > + > + > + > +> htlc_orderbook_multi_index_type; + +typedef generic_index htlc_orderbook_index; + +using account_contact_id_type = object_id; +using htlc_order_id_type = object_id; + +} } //graphene::custom_operations + + +FC_REFLECT_DERIVED( graphene::custom_operations::account_contact_object, (graphene::db::object), + (account)(name)(email)(phone)(address)(company)(url)) +FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::db::object), + (bitshares_account)(bitshares_amount)(blockchain)(blockchain_account)(blockchain_asset) + (blockchain_amount)(expiration)(order_time)(active) + (blockchain_asset_precision)(token_contract)(tag)(taker_bitshares_account) + (taker_blockchain_account)(close_time)) +FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc) ) +FC_REFLECT_ENUM( graphene::custom_operations::blockchains, (eos)(bitcoin)(ripple)(ethereum) ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp new file mode 100644 index 0000000000..c6c1a4916a --- /dev/null +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include + +#include "custom_objects.hpp" + +namespace graphene { namespace custom_operations { + +using namespace std; +using graphene::protocol::account_id_type; + +struct account_contact_operation : chain::base_operation +{ + struct ext + { + optional name; + optional email; + optional phone; + optional address; + optional company; + optional url; + }; + + graphene::protocol::extension extensions; + + void validate()const; +}; + +struct create_htlc_order_operation : chain::base_operation +{ + struct ext + { + optional bitshares_amount; + optional blockchain; + optional blockchain_account; + optional blockchain_asset; + optional blockchain_asset_precision; + optional blockchain_amount; + optional expiration; + optional token_contract; + optional tag; + }; + + graphene::protocol::extension extensions; + + void validate()const; +}; + +struct take_htlc_order_operation : chain::base_operation +{ + struct ext + { + optional htlc_order_id; + optional blockchain_account; + }; + + graphene::protocol::extension extensions; + + void validate()const; +}; + +} } //graphene::custom_operations + +FC_REFLECT( graphene::custom_operations::account_contact_operation::ext, (name)(email)(phone)(address)(company)(url) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::account_contact_operation, (extensions) ) + +FC_REFLECT( graphene::custom_operations::create_htlc_order_operation::ext, (bitshares_amount)(blockchain) + (blockchain_account)(blockchain_asset)(blockchain_asset_precision)(blockchain_amount)(expiration) + (token_contract)(tag) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::create_htlc_order_operation, (extensions) ) + +FC_REFLECT( graphene::custom_operations::take_htlc_order_operation::ext, (htlc_order_id)(blockchain_account) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::take_htlc_order_operation, (extensions) ) + +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp new file mode 100644 index 0000000000..cec86e6611 --- /dev/null +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include + +namespace graphene { namespace custom_operations { +using namespace chain; + +namespace detail +{ + class custom_operations_plugin_impl; +} + +class custom_operations_plugin : public graphene::app::plugin +{ + public: + custom_operations_plugin(); + virtual ~custom_operations_plugin(); + + std::string plugin_name()const override; + std::string plugin_description()const override; + virtual void plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) override; + virtual void plugin_initialize(const boost::program_options::variables_map& options) override; + virtual void plugin_startup() override; + + friend class detail::custom_operations_plugin_impl; + std::unique_ptr my; +}; + + +typedef fc::static_variant< + account_contact_operation, + create_htlc_order_operation, + take_htlc_order_operation +> custom_plugin_operation; + +struct custom_operation_wrapper { + uint8_t unused_data; // if first char of custom_op.data is 0xFF we unpack, this char is not used anymore then. + custom_plugin_operation op; +}; + +struct custom_op_visitor +{ + typedef void result_type; + account_id_type _fee_payer; + database* _db; + + custom_op_visitor(database& db, account_id_type fee_payer) { _db = &db; _fee_payer = fee_payer; }; + + template + void operator()(T &v) const { + v.validate(); + custom_generic_evaluator evaluator(*_db, _fee_payer); + evaluator.do_apply(v); + } +}; + + +} } //graphene::custom_operations + +FC_REFLECT_TYPENAME( graphene::custom_operations::custom_plugin_operation ) +FC_REFLECT( graphene::custom_operations::custom_operation_wrapper, (unused_data)(op) ) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index c3624419bf..60196feb5b 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2014,6 +2014,75 @@ class wallet_api fc::signal lock_changed; std::shared_ptr my; void encrypt_keys(); + + /** + * Add account contact data by using the custom operations plugin. + * + * Each account can optionally add personal information into the blockchain + * to be retrieved by any interested party. + * + * @param account The account ID or name that we are adding additional information to. + * @param data Contact data to be added. \c account_contact_operation::ext + * @param broadcast true if you wish to broadcast the transaction + * + * @return The signed transaction + */ + signed_transaction set_contact_information(string account, account_contact_operation::ext data, bool broadcast); + + /** + * Get contact data of an account by using the custom operations plugin. + * + * If the account added contact data with @ref set_contact_information an \c account_contact_object will be + * returned. + * + * @param account Account ID or name to get contact data from. + * + * @return An \c account_contact_object or empty if account had not provided contact info yet. + */ + optional get_contact_information(string account); + + /** + * Create an HTLC offer using the custom operations plugin. + * + * The \c custom_operations_plugin maintain a list of HTLC offers to facilitate the exchange + * of tokens between bitshares and another blockchain. + * Applications and individuals can create HTLC offers by the use of this command. + * + * @param account The account in the bitshares side. + * @param data Data to create an HTLC offer. \c create_htlc_order_operation::ext + * @param broadcast true if you wish to broadcast the transaction + * + * @return The signed transaction + */ + signed_transaction create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast); + + /** + * Take an HTLC offer using the custom operation plugin. + * + * The \c custom_operations_plugin maintain a list of HTLC offers to facilitate the exchange + * of tokens between bitshares and another blockchain. + * Applications and individuals can take existing HTLC offers by the use of this command. + * Object state will change from active to inactive after the order is taken and will not be displayed by + * @ref get_active_htlc_offers call anymore. + * + * @param account The account of the taker in the bitshares side. + * @param data Data to take an already created and active HTLC offer. \c take_htlc_order_operation::ext data + * @param broadcast true if you wish to broadcast the transaction + * + * @return The signed transaction + */ + signed_transaction take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast); + + /** + * Get active HTLC offers by using the custom operation plugin. + * + * Get the list of offers available at this time to initialize HTLC exchange with another blockchain. + * + * @param blockchain eos = 0 , bitcoin = 1, ripple = 2, ethereum = 3 + * + * @return A list of \c htlc_order_object that are active and non expired in the selected blockchain. + */ + vector get_active_htlc_offers(uint16_t blockchain); }; } } @@ -2221,5 +2290,7 @@ FC_API( graphene::wallet::wallet_api, (blind_history) (receive_blind_transfer) (get_order_book) + (set_contact_information) + (get_contact_information) (quit) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index b96225702b..20eced8820 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -494,7 +494,8 @@ class wallet_api_impl _remote_api(rapi), _remote_db(rapi->database()), _remote_net_broadcast(rapi->network_broadcast()), - _remote_hist(rapi->history()) + _remote_hist(rapi->history()), + _custom_operations(rapi->custom()) { chain_id_type remote_chain_id = _remote_db->get_chain_id(); if( remote_chain_id != _chain_id ) @@ -1960,6 +1961,96 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (htlc_id)(issuer)(seconds_to_add)(broadcast) ) } + signed_transaction set_contact_information(string account, account_contact_operation::ext data, bool broadcast) + { + try + { + FC_ASSERT( !self.is_locked() ); + + account_id_type account_id = get_account(account).id; + + custom_operation op; + account_contact_operation contact; + contact.extensions.value = data; + + auto packed = fc::raw::pack(contact); + packed.insert(packed.begin(), types::account_contact); + packed.insert(packed.begin(), 0xFF); + + op.payer = account_id; + op.data = packed; + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); + tx.validate(); + + return sign_transaction(tx, broadcast); + + } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) + } + + signed_transaction create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast) + { + try + { + FC_ASSERT( !self.is_locked() ); + FC_ASSERT(data.bitshares_amount.valid()); + fc::optional asset_obj = get_asset(data.bitshares_amount->asset_id); + FC_ASSERT(asset_obj, "Could not find asset matching ${asset}", ("asset", data.bitshares_amount->asset_id)); + + account_id_type bitshares_account_id = get_account(account).id; + + custom_operation op; + create_htlc_order_operation htlc; + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::create_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = bitshares_account_id; + op.data = packed; + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); + tx.validate(); + + return sign_transaction(tx, broadcast); + + } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) + } + + signed_transaction take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast) + { + try + { + FC_ASSERT( !self.is_locked() ); + + account_id_type bitshares_account_id = get_account(account).id; + + custom_operation op; + take_htlc_order_operation htlc; + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::take_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = bitshares_account_id; + op.data = packed; + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); + tx.validate(); + + return sign_transaction(tx, broadcast); + + } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) + } + vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) { try { fc::optional vbid = maybe_id( account_name ); @@ -3087,6 +3178,7 @@ class wallet_api_impl fc::api _remote_db; fc::api _remote_net_broadcast; fc::api _remote_hist; + fc::api _custom_operations; optional< fc::api > _remote_net_node; optional< fc::api > _remote_debug; @@ -5186,6 +5278,41 @@ order_book wallet_api::get_order_book( const string& base, const string& quote, return( my->_remote_db->get_order_book( base, quote, limit ) ); } +signed_transaction wallet_api::set_contact_information(string account, account_contact_operation::ext data, + bool broadcast) +{ + return my->set_contact_information(account, data, broadcast); +} + +optional wallet_api::get_contact_information(string account) +{ + return my->_custom_operations->get_contact_info(account); +} + +signed_transaction wallet_api::create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast) +{ + return my->create_htlc_offer(account, data, broadcast); +} + +signed_transaction wallet_api::take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast) +{ + return my->take_htlc_offer(account, data, broadcast); +} + +vector wallet_api::get_active_htlc_offers(uint16_t blockchain) +{ + FC_ASSERT(blockchain <= blockchains::ethereum); + + vector results; + auto orders = my->_custom_operations->get_active_htlc_offers(htlc_order_id_type(0), 100); + for(const auto order : orders) + { + if(order.blockchain == static_cast(blockchain)) + results.push_back(order); + } + return results; +} + signed_block_with_info::signed_block_with_info( const signed_block& block ) : signed_block( block ) { diff --git a/programs/witness_node/CMakeLists.txt b/programs/witness_node/CMakeLists.txt index d671a93c17..674aa5a0a3 100644 --- a/programs/witness_node/CMakeLists.txt +++ b/programs/witness_node/CMakeLists.txt @@ -13,7 +13,7 @@ endif() target_link_libraries( witness_node PRIVATE graphene_app graphene_delayed_node graphene_account_history graphene_elasticsearch graphene_market_history graphene_grouped_orders graphene_witness graphene_chain graphene_debug_witness graphene_egenesis_full graphene_snapshot graphene_es_objects - graphene_api_helper_indexes + graphene_api_helper_indexes graphene_custom_operations fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) install( TARGETS diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 400d09f0ff..506cf9146b 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,7 @@ int main(int argc, char** argv) { auto es_objects_plug = node->register_plugin(); auto grouped_orders_plug = node->register_plugin(); auto api_helper_indexes_plug = node->register_plugin(); + auto custom_operations_plug = node->register_plugin(); // add plugin options to config try diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d05bf13183..2934476a11 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB UNIT_TESTS "tests/*.cpp") add_executable( chain_test ${COMMON_SOURCES} ${UNIT_TESTS} ) target_link_libraries( chain_test graphene_chain graphene_app graphene_witness graphene_account_history graphene_elasticsearch - graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes + graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes graphene_custom_operations fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) @@ -22,6 +22,7 @@ add_executable( performance_test ${COMMON_SOURCES} ${PERFORMANCE_TESTS} ) target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes + graphene_custom_operations fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB BENCH_MARKS "benchmarks/*.cpp") @@ -29,6 +30,7 @@ add_executable( chain_bench ${COMMON_SOURCES} ${BENCH_MARKS} ) target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes + graphene_custom_operations fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB APP_SOURCES "app/*.cpp") @@ -50,6 +52,15 @@ add_executable( es_test ${COMMON_SOURCES} ${ES_SOURCES} ) target_link_libraries( es_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes + graphene_custom_operations fc ${PLATFORM_SPECIFIC_LIBS} ) - + +file(GLOB CUSTOM_SOURCES "custom_operations/*.cpp") +add_executable( custom_operations_test ${COMMON_SOURCES} ${CUSTOM_SOURCES} ) +target_link_libraries( custom_operations_test + graphene_chain graphene_app graphene_account_history graphene_elasticsearch + graphene_es_objects graphene_egenesis_none graphene_api_helper_indexes + graphene_custom_operations + fc ${PLATFORM_SPECIFIC_LIBS} ) + add_subdirectory( generate_empty_blocks ) diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index c2c0278a43..6b2e90d18f 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,30 @@ int get_available_port() return ntohs(sin.sin_port); } +boost::filesystem::path create_api_access_file(fc::temp_directory& directory) { + boost::filesystem::path apiaccess_path = boost::filesystem::path{directory.path().generic_string()} / "api-access.json"; + fc::path apiaccess_out = apiaccess_path; + + const string apiaccess_content = R"( + { + "permission_map" : + [ + [ + "*", + { + "password_hash_b64" : "*", + "password_salt_b64" : "*", + "allowed_apis" : ["database_api", "network_broadcast_api", "history_api", "custom_operations_api"] + } + ] + ] + } + )"; + + fc::json::save_to_file(fc::json::from_string(apiaccess_content), apiaccess_out); + return apiaccess_path; +} + /////////// /// @brief Start the application /// @param app_dir the temporary directory to use @@ -125,7 +150,7 @@ std::shared_ptr start_application(fc::temp_directory app1->register_plugin(true); app1->register_plugin< graphene::market_history::market_history_plugin >(true); app1->register_plugin< graphene::witness_plugin::witness_plugin >(true); - app1->register_plugin< graphene::grouped_orders::grouped_orders_plugin>(true); + app1->register_plugin< graphene::custom_operations::custom_operations_plugin>(true); app1->startup_plugins(); boost::program_options::variables_map cfg; #ifdef _WIN32 @@ -138,6 +163,7 @@ std::shared_ptr start_application(fc::temp_directory ); cfg.emplace("genesis-json", boost::program_options::variable_value(create_genesis_file(app_dir), false)); cfg.emplace("seed-nodes", boost::program_options::variable_value(string("[]"), false)); + cfg.emplace("api-access", boost::program_options::variable_value(create_api_access_file(app_dir), false)); app1->initialize(app_dir.path(), cfg); app1->initialize_plugins(cfg); @@ -145,6 +171,7 @@ std::shared_ptr start_application(fc::temp_directory app1->startup(); fc::usleep(fc::milliseconds(500)); + return app1; } @@ -1182,3 +1209,101 @@ BOOST_FIXTURE_TEST_CASE( cli_sign_message, cli_fixture ) BOOST_CHECK( con.wallet_api_ptr->verify_encapsulated_message( encapsulate( msg ) ) ); } FC_LOG_AND_RETHROW() } + +/////////////////// +// Test the contact information by custom operations plugin +/////////////////// +BOOST_FIXTURE_TEST_CASE( account_contact_information, cli_fixture ) +{ + try { + // just to fund nathan + INVOKE(upgrade_nathan_account); + + BOOST_TEST_MESSAGE("Check account information."); + auto account_contact_info = con.wallet_api_ptr->get_contact_information("nathan"); + BOOST_CHECK(!account_contact_info.valid()); // no info yet + + BOOST_TEST_MESSAGE("About to add contact information."); + + account_contact_operation::ext data; + data.name = "Nathan"; + data.email = "nathan@nathan.com"; + data.phone = "2121212121"; + data.address = "Bv DD 22"; + data.company = ""; + data.url = ""; + + signed_transaction custom_tx = con.wallet_api_ptr->set_contact_information("nathan", data, true); + + BOOST_TEST_MESSAGE("The system is generating a block."); + BOOST_CHECK(generate_block(app1)); + + BOOST_TEST_MESSAGE("Check account contact information."); + account_contact_info = con.wallet_api_ptr->get_contact_information("nathan"); + + BOOST_CHECK_EQUAL(account_contact_info->account.instance.value, 17 ); + BOOST_CHECK_EQUAL(*account_contact_info->name, "Nathan"); + BOOST_CHECK_EQUAL(*account_contact_info->email, "nathan@nathan.com"); + BOOST_CHECK_EQUAL(*account_contact_info->phone, "2121212121"); + BOOST_CHECK_EQUAL(*account_contact_info->address, "Bv DD 22"); + BOOST_CHECK_EQUAL(*account_contact_info->company, ""); + BOOST_CHECK_EQUAL(*account_contact_info->url, ""); + + } catch( fc::exception& e ) { + edump((e.to_detail_string())); + throw; + } +} + +/////////////////// +// Test the htlc offer orderbook by custom operations plugin +/////////////////// +BOOST_FIXTURE_TEST_CASE( htlc_orderbook, cli_fixture ) +{ + try { + // create the taker account + INVOKE(create_new_account); + + auto db = app1->chain_database(); + + BOOST_TEST_MESSAGE("Adding an offer."); + + create_htlc_order_operation::ext data_maker; + data_maker.blockchain = blockchains::bitcoin; + data_maker.blockchain_account = "nathan"; + data_maker.bitshares_amount = asset(100); + data_maker.blockchain_asset = "BTC"; + data_maker.blockchain_amount = "2000"; + data_maker.expiration = db->head_block_time() + 7200; + data_maker.tag = "Some text, can be a memo"; + + signed_transaction custom_tx = con.wallet_api_ptr->create_htlc_offer("nathan", data_maker, true); + + BOOST_TEST_MESSAGE("The system is generating a block."); + BOOST_CHECK(generate_block(app1)); + + BOOST_TEST_MESSAGE("Get active htlc offers."); + auto offers = con.wallet_api_ptr->get_active_htlc_offers(blockchains::bitcoin); + if(offers[0].blockchain == blockchains::bitcoin) { + BOOST_CHECK_EQUAL(offers[0].id.instance(), 0); + } + + BOOST_TEST_MESSAGE("Taking the offfer."); + take_htlc_order_operation::ext data_taker; + data_taker.htlc_order_id = offers[0].id; + data_taker.blockchain_account = "nathan"; + + custom_tx = con.wallet_api_ptr->take_htlc_offer("jmjatlanta", data_taker, true); + + BOOST_TEST_MESSAGE("The system is generating a block."); + BOOST_CHECK(generate_block(app1)); + + BOOST_TEST_MESSAGE("Get active htlc offers."); + offers = con.wallet_api_ptr->get_active_htlc_offers(blockchains::bitcoin); + BOOST_CHECK_EQUAL(offers.size(), 0); + + } catch( fc::exception& e ) { + edump((e.to_detail_string())); + throw; + } +} diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index e25b4f76e0..a4914d8bf7 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -285,6 +286,13 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) ahiplugin->plugin_startup(); } + if(current_test_name == "custom_operations_account_contact_test" || current_test_name == "custom_operations_htlc_bitshares_eos_test") { + auto custom_operations_plugin = app.register_plugin(); + custom_operations_plugin->plugin_set_app(&app); + custom_operations_plugin->plugin_initialize(options); + custom_operations_plugin->plugin_startup(); + } + options.insert(std::make_pair("bucket-size", boost::program_options::variable_value(string("[15]"),false))); mhplugin->plugin_set_app(&app); mhplugin->plugin_initialize(options); diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp new file mode 100644 index 0000000000..3e910705e2 --- /dev/null +++ b/tests/custom_operations/main.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2019 oxarbitrage and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "../common/database_fixture.hpp" + +#define BOOST_TEST_MODULE Custom operations plugin tests +#include + +using namespace graphene::chain; +using namespace graphene::chain::test; +using namespace graphene::app; +using namespace graphene::custom_operations; + +BOOST_FIXTURE_TEST_SUITE( custom_operation_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE(custom_operations_account_contact_test) +{ +try { + ACTORS((nathan)(alice)); + + app.enable_plugin("custom_operations"); + custom_operations_api custom_operations_api(app); + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + enable_fees(); + signed_transaction trx; + set_expiration(db, trx); + + int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); + + transfer(committee_account, nathan_id, asset(init_balance)); + transfer(committee_account, alice_id, asset(init_balance)); + + // nathan adds account data via custom operation + { + custom_operation op; + account_contact_operation contact; + account_contact_operation::ext data; + + data.name = "Nathan"; + data.email = "nathan@nathan.com"; + data.phone = "+1 434343434343"; + data.address = ""; + data.company = "Bitshares"; + data.url = "http://nathan.com/"; + + contact.extensions.value = data; + + auto packed = fc::raw::pack(contact); + packed.insert(packed.begin(), types::account_contact); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // alice adds account data via custom operation + { + custom_operation op; + account_contact_operation contact; + + account_contact_operation::ext data; + data.name = "Alice"; + data.email = "alice@alice.com"; + data.phone = ""; + data.address = "Some Street 456, Somewhere"; + data.company = ""; + data.url = "http://alice.com/"; + + contact.extensions.value = data; + + auto packed = fc::raw::pack(contact); + packed.insert(packed.begin(), types::account_contact); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // check nathan account data with the api + account_contact_object contact_results_nathan = *custom_operations_api.get_contact_info("nathan"); + BOOST_CHECK_EQUAL(contact_results_nathan.account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*contact_results_nathan.name, "Nathan"); + BOOST_CHECK_EQUAL(*contact_results_nathan.email, "nathan@nathan.com"); + BOOST_CHECK_EQUAL(*contact_results_nathan.phone, "+1 434343434343"); + BOOST_CHECK_EQUAL(*contact_results_nathan.address, ""); + BOOST_CHECK_EQUAL(*contact_results_nathan.company, "Bitshares"); + BOOST_CHECK_EQUAL(*contact_results_nathan.url, "http://nathan.com/"); + + // check alice account data with the api + account_contact_object contact_results_alice = *custom_operations_api.get_contact_info("alice"); + BOOST_CHECK_EQUAL(contact_results_alice.account.instance.value, 17 ); + BOOST_CHECK_EQUAL(*contact_results_alice.name, "Alice"); + BOOST_CHECK_EQUAL(*contact_results_alice.email, "alice@alice.com"); + BOOST_CHECK_EQUAL(*contact_results_alice.phone, ""); + BOOST_CHECK_EQUAL(*contact_results_alice.address, "Some Street 456, Somewhere"); + BOOST_CHECK_EQUAL(*contact_results_alice.company, ""); + BOOST_CHECK_EQUAL(*contact_results_alice.url, "http://alice.com/"); + + // alice update her data + { + custom_operation op; + account_contact_operation contact; + + account_contact_operation::ext data; + data.name = "Alice Smith"; + data.email = "alicesmith@alice.com"; + data.phone = "+1 1111 11 1111"; + data.address = "Some Street 456, Somewhere"; + data.company = ""; + data.url = "http://alice.com/"; + + contact.extensions.value = data; + + auto packed = fc::raw::pack(contact); + packed.insert(packed.begin(), types::account_contact); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // check alice account updates with the api + contact_results_alice = *custom_operations_api.get_contact_info("alice"); + BOOST_CHECK_EQUAL(contact_results_alice.account.instance.value, 17 ); + BOOST_CHECK_EQUAL(*contact_results_alice.name, "Alice Smith"); + BOOST_CHECK_EQUAL(*contact_results_alice.email, "alicesmith@alice.com"); + BOOST_CHECK_EQUAL(*contact_results_alice.phone, "+1 1111 11 1111"); + BOOST_CHECK_EQUAL(*contact_results_alice.address, "Some Street 456, Somewhere"); + BOOST_CHECK_EQUAL(*contact_results_alice.company, ""); + BOOST_CHECK_EQUAL(*contact_results_alice.url, "http://alice.com/"); + + // alice try to update nathan data + { + custom_operation op; + account_contact_operation contact; + + account_contact_operation::ext data; + data.name = "Not my account"; + data.phone = "Fake phone"; + data.email = "Fake email"; + data.address = "Fake address"; + data.company = "Fake company"; + data.url = "http://fake.com"; + + contact.extensions.value = data; + + auto packed = fc::raw::pack(contact); + packed.insert(packed.begin(), types::account_contact); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // operation will pass but data will be unchanged, exception was produced in plug in + contact_results_nathan = *custom_operations_api.get_contact_info("nathan"); + BOOST_CHECK(contact_results_nathan.account.instance.value == 16 ); + BOOST_CHECK(*contact_results_nathan.name != "Not my account"); + BOOST_CHECK(*contact_results_nathan.phone != "Fake phone"); + BOOST_CHECK(*contact_results_nathan.email != "Fake email"); +} +catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; +} } + +BOOST_AUTO_TEST_CASE(custom_operations_htlc_bitshares_eos_test) +{ try { + + ACTORS((nathan)(alice)(bob)(carol)); + + app.enable_plugin("custom_operations"); + custom_operations_api custom_operations_api(app); + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + enable_fees(); + signed_transaction trx; + set_expiration(db, trx); + + int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); + + transfer(committee_account, nathan_id, asset(init_balance)); + transfer(committee_account, alice_id, asset(init_balance)); + transfer(committee_account, bob_id, asset(init_balance)); + transfer(committee_account, carol_id, asset(init_balance)); + + enable_fees(); + + // alice creates an order + { + custom_operation op; + create_htlc_order_operation htlc; + + create_htlc_order_operation::ext data; + data.blockchain = blockchains::eos; + data.blockchain_account = "alice"; + data.bitshares_amount = asset(10); + data.blockchain_asset = "EOS"; + data.blockchain_amount = "10"; + data.expiration = db.head_block_time() + fc::seconds(7200); + + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::create_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // bob creates an order + { + custom_operation op; + create_htlc_order_operation htlc; + + create_htlc_order_operation::ext data; + data.blockchain = blockchains::eos; + data.blockchain_account = "bob"; + data.bitshares_amount = asset(100); + data.blockchain_asset = "EOS"; + data.blockchain_amount = "100"; + data.expiration = db.head_block_time() + fc::seconds(7200); + data.tag = "Some text, can be a memo"; + + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::create_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = bob_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + // carol creates an order with missing information (blockchain_amount), will fail in the validator + { + custom_operation op; + create_htlc_order_operation htlc; + + create_htlc_order_operation::ext data; + data.blockchain = blockchains::eos; + data.blockchain_account = "carol"; + data.bitshares_amount = asset(10); + data.blockchain_asset = "EOS"; + data.expiration = db.head_block_time() + fc::seconds(7200); + + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::create_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = carol_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, carol_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // test the get_account_htlc_offers api call for alice + vector htlc_offers_results_alice = custom_operations_api.get_account_htlc_offers("alice", + htlc_order_id_type(0), 100); + BOOST_CHECK_EQUAL(htlc_offers_results_alice.size(), 1); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].id.instance(), 0); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_account.instance.value, 17); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_account, "alice" ); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_amount.amount.value, 10); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_amount, "10"); + BOOST_CHECK(htlc_offers_results_alice[0].active); + + // test the get_htlc_offer api call with alice order + auto htlc_offer = custom_operations_api.get_htlc_offer(htlc_order_id_type(0)); + BOOST_CHECK_EQUAL(htlc_offer->id.instance(), 0); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_account.instance.value, 17); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_account, "alice" ); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.amount.value, 10); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_amount, "10"); + BOOST_CHECK(htlc_offer->active); + + // test the get_account_htlc_offers api call for bob + vector htlc_offers_results_bob = custom_operations_api.get_account_htlc_offers("bob", + htlc_order_id_type(0), 100); + + BOOST_CHECK_EQUAL(htlc_offers_results_bob.size(), 1); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].id.instance(), 1); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_account.instance.value, 18); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_account, "bob" ); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_amount.amount.value, 100); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_amount, "100"); + BOOST_CHECK(htlc_offers_results_bob[0].active); + if(htlc_offers_results_bob[0].tag.valid()) + BOOST_CHECK_EQUAL(*htlc_offers_results_bob[0].tag, "Some text, can be a memo"); + + // get all active offers + vector htlc_offers_results_active = custom_operations_api.get_active_htlc_offers( + htlc_order_id_type(0), 100); + + BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 2); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].id.instance(), 0); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_account.instance.value, 17); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_account, "alice" ); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.amount.value, 10); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_amount, "10"); + BOOST_CHECK(htlc_offers_results_active[0].active); + + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].id.instance(), 1); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_account.instance.value, 18); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_account, "bob" ); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_amount.amount.value, 100); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_amount, "100"); + BOOST_CHECK(htlc_offers_results_active[1].active); + if(htlc_offers_results_active[0].tag.valid()) + BOOST_CHECK_EQUAL(*htlc_offers_results_active[0].tag, "Some text, can be a memo"); + + // nathan takes alice order + { + custom_operation op; + take_htlc_order_operation htlc; + + take_htlc_order_operation::ext data; + data.htlc_order_id = htlc_offers_results_alice[0].id; + data.blockchain_account = "nathan"; + + htlc.extensions.value = data; + + auto packed = fc::raw::pack(htlc); + packed.insert(packed.begin(), types::take_htlc); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // check the taken object + htlc_offer = custom_operations_api.get_htlc_offer(htlc_order_id_type(0)); + BOOST_CHECK_EQUAL(htlc_offer->id.instance(), 0); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_account.instance.value, 17); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_account, "alice" ); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.amount.value, 10); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offer->blockchain_amount, "10"); + BOOST_CHECK(!htlc_offer->active); + BOOST_CHECK_EQUAL(htlc_offer->taker_bitshares_account->instance.value, 16); + BOOST_CHECK_EQUAL(*htlc_offer->taker_blockchain_account, "nathan"); + + // alice order was taken, bob order still up for get_active_htlc_offers + htlc_offers_results_active = custom_operations_api.get_active_htlc_offers(htlc_order_id_type(0), 100); + BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 1); + + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].id.instance(), 1); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_account.instance.value, 18); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_account, "bob"); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.asset_id.instance.value, 0); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.amount.value, 100); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_asset, "EOS"); + BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_amount, "100"); + BOOST_CHECK(htlc_offers_results_active[0].active); + if(htlc_offers_results_active[0].tag.valid()) + BOOST_CHECK_EQUAL(*htlc_offers_results_active[0].tag, "Some text, can be a memo"); + + // make bob order expire + generate_blocks(7201); + fc::usleep(fc::milliseconds(200)); + + htlc_offers_results_active = custom_operations_api.get_active_htlc_offers(htlc_order_id_type(0), 100); + BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 0); +} + +catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; +} } + + +BOOST_AUTO_TEST_SUITE_END() From a3b2e3efc8d91f46117719d4d4e5571758bc46ef Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 16 Aug 2019 14:59:45 -0500 Subject: [PATCH 026/534] Reset flag after testing compiler --- CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd9db30bf5..43f1dd40bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,9 @@ macro(FIND_CURL) endif (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) endmacro() +# Save the old value of CMAKE_REQUIRED_FLAGS +set( TEMP_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ) + # Fortify source if (CMAKE_COMPILER_IS_GNUCXX) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -91,6 +94,8 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif () endif () +set(CMAKE_REQUIRED_FLAGS ${TEMP_REQUIRED_FLAGS} ) + # check for Data relocation and Protection (RELRO) set(CMAKE_REQUIRED_FLAGS "-Wl,-zrelro,-znow") check_c_compiler_flag("" HAVE_RELROFULL) @@ -108,6 +113,8 @@ else() endif() endif() +set(CMAKE_REQUIRED_FLAGS ${TEMP_REQUIRED_FLAGS} ) + # position independent executetable (PIE) # position independent code (PIC) add_definitions (-fPIC) From c3ebbc6fb7f09ba6f233d3c363d8b08b2e857255 Mon Sep 17 00:00:00 2001 From: manikey123 Date: Sun, 18 Aug 2019 20:01:47 -0700 Subject: [PATCH 027/534] Change 1: made on review comments --- libraries/app/application.cpp | 52 +++++++++++++++--------------- libraries/app/database_api.cpp | 24 ++++++-------- tests/tests/database_api_tests.cpp | 43 +++++++----------------- 3 files changed, 47 insertions(+), 72 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 601afc2904..7e9d54dbe8 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -1048,57 +1048,57 @@ void application::set_program_options(boost::program_options::options_descriptio "Whether to enable tracking of votes of standby witnesses and committee members. " "Set it to true to provide accurate data to API clients, set to false for slightly better performance.") ("api-limit-get-account-history-operations",boost::program_options::value()->default_value(100), - "For history_api::get_account_history_operations to set its default limit value as 100") + "For history_api::get_account_history_operations to set max limit value") ("api-limit-get-account-history",boost::program_options::value()->default_value(100), - "For history_api::get_account_history to set its default limit value as 100") + "For history_api::get_account_history to set max limit value") ("api-limit-get-grouped-limit-orders",boost::program_options::value()->default_value(101), - "For orders_api::get_grouped_limit_orders to set its default limit value as 101") + "For orders_api::get_grouped_limit_orders to set max limit value") ("api-limit-get-relative-account-history",boost::program_options::value()->default_value(100), - "For history_api::get_relative_account_history to set its default limit value as 100") + "For history_api::get_relative_account_history to set max limit value") ("api-limit-get-account-history-by-operations",boost::program_options::value()->default_value(100), - "For history_api::get_account_history_by_operations to set its default limit value as 100") + "For history_api::get_account_history_by_operations to set max limit value") ("api-limit-get-asset-holders",boost::program_options::value()->default_value(100), - "For asset_api::get_asset_holders to set its default limit value as 100") + "For asset_api::get_asset_holders to set max limit value") ("api-limit-get-key-references",boost::program_options::value()->default_value(100), - "For database_api_impl::get_key_references to set its default limit value as 100") + "For database_api_impl::get_key_references to set max limit value") ("api-limit-get-htlc-by",boost::program_options::value()->default_value(100), - "For database_api_impl::get_htlc_by_from and get_htlc_by_to to set its default limit value as 100") + "For database_api_impl::get_htlc_by_from and get_htlc_by_to to set max limit value") ("api-limit-get-full-accounts",boost::program_options::value()->default_value(10), - "For database_api_impl::get_full_accounts to set its account default limit values as 10") + "For database_api_impl::get_full_accounts to set max limit value") ("api-limit-get-full-accounts-lists",boost::program_options::value()->default_value(100), - "For database_api_impl::get_full_accounts to set its lists default limit values as 100") + "For database_api_impl::get_full_accounts to set max limit value") ("api-limit-get-call-orders",boost::program_options::value()->default_value(300), - "For database_api_impl::get_call_orders and get_call_orders_by_account to set its default limit values as 300") + "For database_api_impl::get_call_orders and get_call_orders_by_account to set max limit value") ("api-limit-get-settle-orders",boost::program_options::value()->default_value(300), - "For database_api_impl::get_settle_orders and get_settle_orders_by_account to set its default limit values as 300") + "For database_api_impl::get_settle_orders and get_settle_orders_by_account to set max limit value") ("api-limit-get-assets",boost::program_options::value()->default_value(101), - "For database_api_impl::list_assets and get_assets_by_issuer to set its default limit values as 101") + "For database_api_impl::list_assets and get_assets_by_issuer to set max limit value") ("api-limit-get-limit-orders",boost::program_options::value()->default_value(300), - "For database_api_impl::get_limit_orders to set its default limit value as 300") + "For database_api_impl::get_limit_orders to set max limit value") ("api-limit-get-order-book",boost::program_options::value()->default_value(50), - "For database_api_impl::get_order_book to set its default limit value as 50") + "For database_api_impl::get_order_book to set max limit value") ("api-limit-lookup-accounts",boost::program_options::value()->default_value(1000), - "For database_api_impl::lookup_accounts to set its default limit values as 1000") + "For database_api_impl::lookup_accounts to set max limit value") ("api-limit-lookup-witness-accounts",boost::program_options::value()->default_value(1000), - "For database_api_impl::lookup_witness_accounts to set its default limit values as 1000") + "For database_api_impl::lookup_witness_accounts to set max limit value") ("api-limit-lookup-committee-member-accounts",boost::program_options::value()->default_value(1000), - "For database_api_impl::lookup_committee_member_accounts to set its default limit values as 1000") + "For database_api_impl::lookup_committee_member_accounts to set max limit value") ("api-limit-lookup-vote-ids",boost::program_options::value()->default_value(1000), - "For database_api_impl::lookup_vote_ids to set its default limit values as 1000") + "For database_api_impl::lookup_vote_ids to set max limit value") ("api-limit-get-account-limit-orders",boost::program_options::value()->default_value(101), - "For database_api_impl::get_account_limit_orders to set its default limit values as 101") + "For database_api_impl::get_account_limit_orders to set max limit value") ("api-limit-get-collateral-bids",boost::program_options::value()->default_value(100), - "For database_api_impl::get_collateral_bids to set its default limit values as 100") + "For database_api_impl::get_collateral_bids to set max limit value") ("api-limit-get-top-markets",boost::program_options::value()->default_value(100), - "For database_api_impl::get_top_markets to set its default limit values as 100") + "For database_api_impl::get_top_markets to set max limit value") ("api-limit-get-trade-history",boost::program_options::value()->default_value(100), - "For database_api_impl::get_trade_history to set its default limit values as 100") + "For database_api_impl::get_trade_history to set max limit value") ("api-limit-get-trade-history-by-sequence",boost::program_options::value()->default_value(100), - "For database_api_impl::get_trade_history_by_sequence to set its default limit values as 100") + "For database_api_impl::get_trade_history_by_sequence to set max limit value") ("api-limit-get-withdraw-permissions-by-giver",boost::program_options::value()->default_value(101), - "For database_api_impl::get_withdraw_permissions_by_giver to set its default limit values as 101") + "For database_api_impl::get_withdraw_permissions_by_giver to set max limit value") ("api-limit-get-withdraw-permissions-by-recipient",boost::program_options::value()->default_value(101), - "For database_api_impl::get_withdraw_permissions_by_recipient to set its default limit values as 101") + "For database_api_impl::get_withdraw_permissions_by_recipient to set max limit value") ; command_line_options.add(configuration_file_options); command_line_options.add_options() diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 79f668566c..ee1300677d 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -864,8 +864,7 @@ vector database_api::get_account_limit_orders( const string& vector database_api_impl::get_account_limit_orders( const string& account_name_or_id, const string &base, const string "e, uint32_t limit, optional ostart_id, optional ostart_price) { - uint64_t api_limit_get_account_limit_orders =_app_options->api_limit_get_account_limit_orders; - FC_ASSERT( limit <= api_limit_get_account_limit_orders ); + FC_ASSERT( limit <= _app_options->api_limit_get_account_limit_orders ); vector results; uint32_t count = 0; @@ -1170,8 +1169,7 @@ map database_api::lookup_accounts(const string& lower_bo map database_api_impl::lookup_accounts(const string& lower_bound_name, uint32_t limit)const { - uint64_t api_limit_lookup_accounts = _app_options->api_limit_lookup_accounts; - FC_ASSERT( limit <= api_limit_lookup_accounts ); + FC_ASSERT( limit <= _app_options->api_limit_lookup_accounts ); const auto& accounts_by_name = _db.get_index_type().indices().get(); map result; @@ -1580,8 +1578,7 @@ vector database_api::get_collateral_bids(const std::strin vector database_api_impl::get_collateral_bids(const std::string& asset, uint32_t limit, uint32_t skip)const { try { - uint64_t api_limit_get_collateral_bids=_app_options->api_limit_get_collateral_bids; - FC_ASSERT( limit <= api_limit_get_collateral_bids ); + FC_ASSERT( limit <= _app_options->api_limit_get_collateral_bids ); const asset_id_type asset_id = get_asset_from_string(asset)->id; const asset_object& swan = asset_id(_db); FC_ASSERT( swan.is_market_issued() ); @@ -1592,7 +1589,8 @@ vector database_api_impl::get_collateral_bids(const std:: auto start = aidx.lower_bound( boost::make_tuple( asset_id, price::max(back.id, asset_id), collateral_bid_id_type() ) ); auto end = aidx.lower_bound( boost::make_tuple( asset_id, price::min(back.id, asset_id), collateral_bid_id_type(GRAPHENE_DB_MAX_INSTANCE_ID) ) ); vector result; - if(skipapi_limit_get_order_book; - FC_ASSERT( limit <= api_limit_get_order_book ); + FC_ASSERT( limit <= _app_options->api_limit_get_order_book ); order_book result; result.base = base; @@ -2016,8 +2013,7 @@ map database_api::lookup_witness_accounts(const string& map database_api_impl::lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const { - uint64_t api_limit_lookup_witness_accounts = _app_options->api_limit_lookup_witness_accounts; - FC_ASSERT( limit <= api_limit_lookup_witness_accounts ); + FC_ASSERT( limit <= _app_options->api_limit_lookup_witness_accounts ); const auto& witnesses_by_id = _db.get_index_type().indices().get(); // we want to order witnesses by account name, but that name is in the account object @@ -2093,8 +2089,7 @@ map database_api::lookup_committee_member_acco map database_api_impl::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const { - uint64_t api_limit_lookup_committee_member_accounts = _app_options->api_limit_lookup_committee_member_accounts; - FC_ASSERT( limit <= api_limit_lookup_committee_member_accounts ); + FC_ASSERT( limit <= _app_options->api_limit_lookup_committee_member_accounts ); const auto& committee_members_by_id = _db.get_index_type().indices().get(); // we want to order committee_members by account name, but that name is in the account object @@ -2192,8 +2187,7 @@ vector database_api::lookup_vote_ids( const vector& votes vector database_api_impl::lookup_vote_ids( const vector& votes )const { - uint64_t api_limit_lookup_vote_ids = _app_options->api_limit_lookup_vote_ids; - FC_ASSERT( votes.size() < api_limit_lookup_vote_ids, "Only 1000 votes can be queried at a time" ); + FC_ASSERT( votes.size() < _app_options->api_limit_lookup_vote_ids ); const auto& witness_idx = _db.get_index_type().indices().get(); const auto& committee_idx = _db.get_index_type().indices().get(); diff --git a/tests/tests/database_api_tests.cpp b/tests/tests/database_api_tests.cpp index 22384e847e..5f92933653 100644 --- a/tests/tests/database_api_tests.cpp +++ b/tests/tests/database_api_tests.cpp @@ -981,6 +981,7 @@ BOOST_AUTO_TEST_CASE( subscription_notification_test ) BOOST_AUTO_TEST_CASE( lookup_vote_ids ) { try { + graphene::app::database_api db_api( db, &( app.get_options() )); ACTORS( (connie)(whitney)(wolverine) ); fund(connie); @@ -994,8 +995,6 @@ BOOST_AUTO_TEST_CASE( lookup_vote_ids ) const auto& witness = create_witness( whitney ); const auto& worker = create_worker( wolverine_id ); - graphene::app::database_api db_api(db); - std::vector votes; votes.push_back( committee.vote_id ); votes.push_back( witness.vote_id ); @@ -1007,7 +1006,7 @@ BOOST_AUTO_TEST_CASE( lookup_vote_ids ) BOOST_AUTO_TEST_CASE(get_account_limit_orders) { try { - + graphene::app::database_api db_api( db, &( app.get_options() )); ACTORS((seller)); const auto& bitcny = create_bitasset("CNY"); @@ -1029,7 +1028,6 @@ BOOST_AUTO_TEST_CASE(get_account_limit_orders) BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250 - i))); } - graphene::app::database_api db_api(db); std::vector results; limit_order_object o; @@ -1682,11 +1680,7 @@ BOOST_AUTO_TEST_CASE( asset_in_collateral ) BOOST_AUTO_TEST_CASE( api_limit_lookup_accounts ) { try{ graphene::app::database_api db_api( db, &( app.get_options() )); - auto bob_private_key = generate_private_key("bob"); - account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; - transfer(account_id_type(), bob_id, asset(100)); - generate_block(); - fc::usleep(fc::milliseconds(100)); + ACTOR(bob); GRAPHENE_CHECK_THROW(db_api.lookup_accounts("bob",220), fc::exception); map result =db_api.lookup_accounts("bob",190); BOOST_REQUIRE_EQUAL( result.size(), 17u); @@ -1700,11 +1694,7 @@ BOOST_AUTO_TEST_CASE( api_limit_lookup_accounts ) { BOOST_AUTO_TEST_CASE( api_limit_lookup_witness_accounts ) { try{ graphene::app::database_api db_api( db, &( app.get_options() )); - auto bob_private_key = generate_private_key("bob"); - account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; - transfer(account_id_type(), bob_id, asset(100)); - generate_block(); - fc::usleep(fc::milliseconds(100)); + ACTORS((bob)) ; GRAPHENE_CHECK_THROW(db_api.lookup_witness_accounts("bob",220), fc::exception); map result =db_api.lookup_witness_accounts("bob",190); BOOST_REQUIRE_EQUAL( result.size(), 10u); @@ -1738,7 +1728,6 @@ BOOST_AUTO_TEST_CASE(api_limit_get_withdraw_permissions_by_recipient){ graphene::app::database_api db_api( db, &app.get_options()); ACTORS((bob)) ; withdraw_permission_id_type withdraw_permission; - transfer(account_id_type(), bob_id, asset(100)); GRAPHENE_CHECK_THROW(db_api.get_withdraw_permissions_by_recipient( "bob",withdraw_permission, 251), fc::exception); vector result =db_api.get_withdraw_permissions_by_recipient( @@ -1754,7 +1743,6 @@ BOOST_AUTO_TEST_CASE(api_limit_get_withdraw_permissions_by_giver){ graphene::app::database_api db_api( db, &app.get_options()); ACTORS((bob)) ; withdraw_permission_id_type withdraw_permission; - transfer(account_id_type(), bob_id, asset(100)); GRAPHENE_CHECK_THROW(db_api.get_withdraw_permissions_by_giver( "bob",withdraw_permission, 251), fc::exception); vector result =db_api.get_withdraw_permissions_by_giver( @@ -1771,19 +1759,18 @@ BOOST_AUTO_TEST_CASE(api_limit_get_trade_history_by_sequence){ graphene::app::application_options opt=app.get_options(); opt.has_market_history_plugin = true; graphene::app::database_api db_api( db, &opt); - ACTORS((bob) (alice) (fred)) ; - const auto& bitusd = create_bitasset("USDBIT", bob_id); + const auto& bitusd = create_bitasset("USDBIT"); asset_id_type asset_1, asset_2; asset_1 = bitusd.id; asset_2 = asset_id_type(); GRAPHENE_CHECK_THROW(db_api.get_trade_history_by_sequence( std::string( static_cast(asset_1)), std::string( static_cast(asset_2)), - 0,fc::time_point_sec(1532008940), 251), fc::exception); + 0,fc::time_point_sec(), 251), fc::exception); vector result =db_api.get_trade_history_by_sequence( std::string( static_cast(asset_1)), std::string( static_cast(asset_2)), - 0,fc::time_point_sec(1532008940),250); + 0,fc::time_point_sec(),250); BOOST_REQUIRE_EQUAL( result.size(), 0u); }catch (fc::exception& e) { edump((e.to_detail_string())); @@ -1797,20 +1784,19 @@ BOOST_AUTO_TEST_CASE(api_limit_get_trade_history){ graphene::app::application_options opt=app.get_options(); opt.has_market_history_plugin = true; graphene::app::database_api db_api( db, &opt); - ACTORS((bob) (alice) (fred)) ; - const auto& bitusd = create_bitasset("USDBIT", bob_id); + const auto& bitusd = create_bitasset("USDBIT"); asset_id_type asset_1, asset_2; asset_1 = bitusd.id; asset_2 = asset_id_type(); GRAPHENE_CHECK_THROW(db_api.get_trade_history( std::string( static_cast(asset_1)), std::string( static_cast(asset_2)), - fc::time_point_sec(1532008920),fc::time_point_sec(1532008940), + fc::time_point_sec(),fc::time_point_sec(), 251), fc::exception); vector result =db_api.get_trade_history( std::string( static_cast(asset_1)), std::string( static_cast(asset_2)), - fc::time_point_sec(1532008920),fc::time_point_sec(1532008940),250); + fc::time_point_sec(),fc::time_point_sec(),250); BOOST_REQUIRE_EQUAL( result.size(), 0u); }catch (fc::exception& e) { edump((e.to_detail_string())); @@ -1823,8 +1809,7 @@ BOOST_AUTO_TEST_CASE(api_limit_get_top_markets){ graphene::app::application_options opt=app.get_options(); opt.has_market_history_plugin = true; graphene::app::database_api db_api( db, &opt); - ACTORS((bob) (alice) (fred)) ; - const auto& bitusd = create_bitasset("USDBIT", bob_id); + const auto& bitusd = create_bitasset("USDBIT"); asset_id_type asset_1, asset_2; asset_1 = bitusd.id; asset_2 = asset_id_type(); @@ -1970,11 +1955,7 @@ BOOST_AUTO_TEST_CASE( api_limit_lookup_vote_ids ) { BOOST_AUTO_TEST_CASE( api_limit_lookup_committee_member_accounts ) { try{ graphene::app::database_api db_api( db, &( app.get_options() )); - auto bob_private_key = generate_private_key("bob"); - account_id_type bob_id = create_account("bob", bob_private_key.get_public_key()).id; - transfer(account_id_type(), bob_id, asset(100)); - generate_block(); - fc::usleep(fc::milliseconds(100)); + ACTORS((bob)); GRAPHENE_CHECK_THROW(db_api.lookup_committee_member_accounts("bob",220), fc::exception); std::map result =db_api.lookup_committee_member_accounts("bob",190); BOOST_REQUIRE_EQUAL( result.size(), 10u); From 9e28eccdb86b9afca01651a7277daab7f21caa6d Mon Sep 17 00:00:00 2001 From: manikey123 Date: Sun, 18 Aug 2019 23:50:14 -0700 Subject: [PATCH 028/534] Merge changes --- libraries/app/database_api.cpp | 2 +- tests/tests/database_api_tests.cpp | 4 ++-- tests/tests/swan_tests.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 588f1bca99..1cca257b45 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -982,7 +982,7 @@ vector database_api_impl::get_account_limit_orders( const string& account_name_or_id, const string &base, const string "e, uint32_t limit, optional ostart_id, optional ostart_price ) { - FC_ASSERT( limit <= 101 ); + FC_ASSERT( limit <= _app_options->api_limit_get_account_limit_orders ); vector results; uint32_t count = 0; diff --git a/tests/tests/database_api_tests.cpp b/tests/tests/database_api_tests.cpp index 76a339f376..a577f7a281 100644 --- a/tests/tests/database_api_tests.cpp +++ b/tests/tests/database_api_tests.cpp @@ -2007,7 +2007,7 @@ BOOST_AUTO_TEST_CASE(api_limit_get_collateral_bids) { } BOOST_AUTO_TEST_CASE(api_limit_get_account_limit_orders) { try { - + graphene::app::database_api db_api( db, &( app.get_options() )); ACTORS((seller)); const auto &bitcny = create_bitasset("CNY"); const auto &core = asset_id_type()(db); @@ -2020,7 +2020,7 @@ BOOST_AUTO_TEST_CASE(api_limit_get_account_limit_orders) { BOOST_CHECK(create_sell_order(seller, core.amount(100), bitcny.amount(250+i))); } - graphene::app::database_api db_api( db, &( app.get_options() )); + std::vector results=db_api.get_account_limit_orders(seller.name, GRAPHENE_SYMBOL, "CNY",250); BOOST_REQUIRE_EQUAL( results.size(), 250u); GRAPHENE_CHECK_THROW( db_api.get_account_limit_orders(seller.name, GRAPHENE_SYMBOL, "CNY",251), fc::exception); diff --git a/tests/tests/swan_tests.cpp b/tests/tests/swan_tests.cpp index 54f233c66a..d5aff8b996 100644 --- a/tests/tests/swan_tests.cpp +++ b/tests/tests/swan_tests.cpp @@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE( recollateralize ) bid_collateral( borrower2(), back().amount(2100), swan().amount(1399) ); // check get_collateral_bids - graphene::app::database_api db_api(db); + graphene::app::database_api db_api( db, &( app.get_options() )); GRAPHENE_REQUIRE_THROW( db_api.get_collateral_bids(back().symbol, 100, 0), fc::assert_exception ); auto swan_symbol = _swan(db).symbol; vector bids = db_api.get_collateral_bids(swan_symbol, 100, 1); @@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE( revive_empty_with_bid ) // revive wait_for_maintenance(); BOOST_CHECK( !swan().bitasset_data(db).has_settlement() ); - graphene::app::database_api db_api(db); + graphene::app::database_api db_api( db, &( app.get_options() )); auto swan_symbol = _swan(db).symbol; vector bids = db_api.get_collateral_bids(swan_symbol, 100, 0); BOOST_CHECK( bids.empty() ); From 89bb143c95389ce4f98f7c7f08422d93f8a5d9cd Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Tue, 20 Aug 2019 15:11:58 +0200 Subject: [PATCH 029/534] Add warning for bad choice of GRAPHENE_PREGENERATE_FILES --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc287f29f..f71a352cd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,19 @@ set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" ) set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) -SET( GRAPHENE_PREGENERATE_FILES OFF CACHE BOOL +set( GRAPHENE_PREGENERATE_FILES OFF CACHE BOOL "ON for pre-creating generated sources instead of during the build. Useful for cross-compilation." ) +if( CMAKE_CROSSCOMPILING ) + message(STATUS "Cross-compilation detected.") + if( NOT(GRAPHENE_PREGENERATE_FILES) ) + message( WARNING "Hint: set GRAPHENE_PREGENERATE_FILES=ON to avoid problems with cat-parts and egenesis!" ) + endif( NOT(GRAPHENE_PREGENERATE_FILES) ) +else( CMAKE_CROSSCOMPILING ) + message(STATUS "Native build detected") + if( GRAPHENE_PREGENERATE_FILES ) + message( WARNING "Hint: set GRAPHENE_PREGENERATE_FILES=OFF to avoid stale dependencies!" ) + endif( GRAPHENE_PREGENERATE_FILES ) +endif( CMAKE_CROSSCOMPILING ) if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) set( CMAKE_CXX_EXTENSIONS ON ) # for __int128 support From cd8cd99c130768ae3b1b6cab7fb6ecd26df1bead Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Tue, 20 Aug 2019 15:39:19 +0200 Subject: [PATCH 030/534] Handle re-generation of hardfork.hpp + embed_genesis properly, get rid of c++ helpers --- CMakeLists.txt | 14 -- libraries/chain/CMakeLists.txt | 26 +-- libraries/egenesis/CMakeLists.txt | 84 +++----- libraries/egenesis/embed_genesis.cpp | 288 -------------------------- programs/build_helpers/CMakeLists.txt | 17 +- programs/build_helpers/cat-parts.cpp | 78 ------- 6 files changed, 43 insertions(+), 464 deletions(-) delete mode 100644 libraries/egenesis/embed_genesis.cpp delete mode 100644 programs/build_helpers/cat-parts.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f71a352cd5..bd9db30bf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,20 +12,6 @@ set( INSTALLER_APP_ID "68ad7005-8eee-49c9-95ce-9eed97e5b347" ) set( CMAKE_CXX_STANDARD 14 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) -set( GRAPHENE_PREGENERATE_FILES OFF CACHE BOOL - "ON for pre-creating generated sources instead of during the build. Useful for cross-compilation." ) -if( CMAKE_CROSSCOMPILING ) - message(STATUS "Cross-compilation detected.") - if( NOT(GRAPHENE_PREGENERATE_FILES) ) - message( WARNING "Hint: set GRAPHENE_PREGENERATE_FILES=ON to avoid problems with cat-parts and egenesis!" ) - endif( NOT(GRAPHENE_PREGENERATE_FILES) ) -else( CMAKE_CROSSCOMPILING ) - message(STATUS "Native build detected") - if( GRAPHENE_PREGENERATE_FILES ) - message( WARNING "Hint: set GRAPHENE_PREGENERATE_FILES=OFF to avoid stale dependencies!" ) - endif( GRAPHENE_PREGENERATE_FILES ) -endif( CMAKE_CROSSCOMPILING ) - if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) set( CMAKE_CXX_EXTENSIONS ON ) # for __int128 support else( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 04905c6b66..8679fe83a4 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -69,21 +69,17 @@ add_library( graphene_chain "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) -if( GRAPHENE_PREGENERATE_FILES ) - message( STATUS "Generating hardfork.hpp" ) - file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/" ) - file( REMOVE "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) - file( GLOB HARDFORKS "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d/*" ) - foreach( HF ${HARDFORKS} ) - file( READ "${HF}" INCL ) - file( APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" "${INCL}" ) - endforeach( HF ) -else( GRAPHENE_PREGENERATE_FILES ) - add_custom_target( build_hardfork_hpp - COMMAND cat-parts "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d" "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) - add_dependencies( build_hardfork_hpp cat-parts ) - add_dependencies( graphene_chain build_hardfork_hpp ) -endif( GRAPHENE_PREGENERATE_FILES ) +message( STATUS "Generating hardfork.hpp" ) +file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/" ) +file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tmp/" ) +file( REMOVE "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) +file( GLOB HARDFORKS "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d/*" ) +foreach( HF ${HARDFORKS} ) + file( READ "${HF}" INCL ) + file( APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" "${INCL}" ) + get_filename_component( _HF "${HF}" NAME ) + configure_file( "${HF}" "${CMAKE_CURRENT_BINARY_DIR}/tmp/${_HF}.tmp") +endforeach( HF ) target_link_libraries( graphene_chain fc graphene_db graphene_protocol ) target_include_directories( graphene_chain diff --git a/libraries/egenesis/CMakeLists.txt b/libraries/egenesis/CMakeLists.txt index c2d03407d4..74549d8817 100644 --- a/libraries/egenesis/CMakeLists.txt +++ b/libraries/egenesis/CMakeLists.txt @@ -1,59 +1,31 @@ - -if( GRAPHENE_PREGENERATE_FILES ) - message( STATUS "Generating egenesis" ) - file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) - - if( GRAPHENE_EGENESIS_JSON ) - set( embed_genesis_args "${GRAPHENE_EGENESIS_JSON}" ) - else( GRAPHENE_EGENESIS_JSON ) - set( embed_genesis_args "genesis.json" ) - endif( GRAPHENE_EGENESIS_JSON ) - file( SHA256 "${embed_genesis_args}" chain_id ) - set( generated_file_banner "/*** GENERATED FILE - DO NOT EDIT! ***/" ) - set( genesis_json_hash "${chain_id}" ) - configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" ) - - file( READ "${embed_genesis_args}" genesis_json ) - string( LENGTH "${genesis_json}" genesis_json_length ) - string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) - string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) - string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) - set( genesis_json_array "\"${genesis_json_escaped}\"" ) - set( genesis_json_array_height 1 ) - set( genesis_json_array_width ${genesis_json_length} ) - configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) - -else( GRAPHENE_PREGENERATE_FILES ) - add_executable( embed_genesis embed_genesis.cpp ) - target_link_libraries( embed_genesis graphene_chain graphene_app graphene_egenesis_none fc ) - set( embed_genesis_args - -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" - -t "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl---${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" - ) - - MESSAGE( STATUS "egenesis: " ${GRAPHENE_EGENESIS_JSON} ) - - if( GRAPHENE_EGENESIS_JSON ) - list( APPEND embed_genesis_args --genesis-json "${GRAPHENE_EGENESIS_JSON}" ) - endif( GRAPHENE_EGENESIS_JSON ) - - MESSAGE( STATUS "embed_genesis_args: " ${embed_genesis_args} ) - - add_custom_command( - OUTPUT - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMAND embed_genesis ${embed_genesis_args} - DEPENDS - "${GRAPHENE_EGENESIS_JSON}" - "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" - "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" - embed_genesis ) - -endif( GRAPHENE_PREGENERATE_FILES ) +message( STATUS "Generating egenesis" ) + +if( GRAPHENE_EGENESIS_JSON ) + set( embed_genesis_args "${GRAPHENE_EGENESIS_JSON}" ) +else( GRAPHENE_EGENESIS_JSON ) + set( embed_genesis_args "genesis.json" ) +endif( GRAPHENE_EGENESIS_JSON ) + +file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tmp/" ) +configure_file( "${embed_genesis_args}" + "${CMAKE_CURRENT_BINARY_DIR}/tmp/genesis" ) + +file( SHA256 "${embed_genesis_args}" chain_id ) +set( generated_file_banner "/*** GENERATED FILE - DO NOT EDIT! ***/" ) +set( genesis_json_hash "${chain_id}" ) +configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" ) + +file( READ "${embed_genesis_args}" genesis_json ) +string( LENGTH "${genesis_json}" genesis_json_length ) +string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) +string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) +string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) +set( genesis_json_array "\"${genesis_json_escaped}\"" ) +set( genesis_json_array_height 1 ) +set( genesis_json_array_width ${genesis_json_length} ) +configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) add_library( graphene_egenesis_none egenesis_none.cpp include/graphene/egenesis/egenesis.hpp ) diff --git a/libraries/egenesis/embed_genesis.cpp b/libraries/egenesis/embed_genesis.cpp deleted file mode 100644 index a23a32b80c..0000000000 --- a/libraries/egenesis/embed_genesis.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2015 Cryptonomex, Inc., and contributors. - * - * The MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -// we need to include the world in order to serialize fee_parameters -#include - -using namespace graphene::chain; - -static const char generated_file_banner[] = -"// _ _ __ _ _ //\n" -"// | | | | / _(_) | //\n" -"// __ _ ___ _ __ ___ _ __ __ _| |_ ___ __| | | |_ _| | ___ //\n" -"// / _` |/ _ \\ '_ \\ / _ \\ '__/ _` | __/ _ \\/ _` | | _| | |/ _ \\ //\n" -"// | (_| | __/ | | | __/ | | (_| | || __/ (_| | | | | | | __/ //\n" -"// \\__, |\\___|_| |_|\\___|_| \\__,_|\\__\\___|\\__,_| |_| |_|_|\\___| //\n" -"// __/ | //\n" -"// |___/ //\n" -"// //\n" -"// Generated by: libraries/chain_id/identify_chain.cpp //\n" -"// //\n" -"// Warning: This is a generated file, any changes made here will be //\n" -"// overwritten by the build process. If you need to change what //\n" -"// is generated here, you should use the CMake variable //\n" -"// GRAPHENE_EGENESIS_JSON to specify an embedded genesis state. //\n" -"// //\n" -; - -// hack: import create_example_genesis() even though it's a way, way -// specific internal detail -namespace graphene { namespace app { namespace detail { -genesis_state_type create_example_genesis(); -} } } // graphene::app::detail - -fc::path get_path( - const boost::program_options::variables_map& options, - const std::string& name ) -{ - fc::path result = options[name].as(); - if( result.is_relative() ) - result = fc::current_path() / result; - return result; -} - -void convert_to_c_array( - const std::string& src, - std::string& dest, - int width = 40 ) -{ - dest.reserve( src.length() * 6 / 5 ); - bool needs_comma = false; - int row = 0; - for( std::string::size_type i=0; i': case '@': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - case '[': case ']': case '^': case '_': case '`': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case '{': case '|': case '}': case '~': - dest.append(&c, 1); - break; - - // use shortest octal escape for everything else - default: - dest.append("\\"); - char dg[3]; - dg[0] = '0' + ((c >> 6) & 3); - dg[1] = '0' + ((c >> 3) & 7); - dg[2] = '0' + ((c ) & 7); - int start = (dg[0] == '0' ? (dg[1] == '0' ? 2 : 1) : 0); - dest.append( dg+start, 3-start ); - } - } - dest.append("\""); - needs_comma = true; - row++; - } - std::cerr << "\n"; - return; -} - -struct egenesis_info -{ - fc::optional< genesis_state_type > genesis; - fc::optional< chain_id_type > chain_id; - fc::optional< std::string > genesis_json; - fc::optional< fc::sha256 > genesis_json_hash; - fc::optional< std::string > genesis_json_array; - int genesis_json_array_width, - genesis_json_array_height; - - void fillin() - { - // must specify either genesis_json or genesis - if( genesis.valid() ) - { - if( !genesis_json.valid() ) - // If genesis_json not exist, generate from genesis - genesis_json = fc::json::to_string( *genesis ); - } - else if( genesis_json.valid() ) - { - // If genesis not exist, generate from genesis_json - genesis = fc::json::from_string( *genesis_json ).as< genesis_state_type >( 20 ); - } - else - { - // Neither genesis nor genesis_json exists, crippled - std::cerr << "embed_genesis: Need genesis or genesis_json\n"; - exit(1); - } - // init genesis_json_hash from genesis_json - if( !genesis_json_hash.valid() ) - genesis_json_hash = fc::sha256::hash( *genesis_json ); - // init chain_id from genesis_json_hash - if( !chain_id.valid() ) - chain_id = genesis_json_hash; - // init genesis_json_array from genesis_json - if( !genesis_json_array.valid() ) - { - genesis_json_array = std::string(); - // TODO: gzip - int width = 40; - convert_to_c_array( *genesis_json, *genesis_json_array, width ); - int height = (genesis_json->length() + width-1) / width; - genesis_json_array_width = width; - genesis_json_array_height = height; - } - } -}; - -void load_genesis( - const boost::program_options::variables_map& options, - egenesis_info& info - ) -{ - if( options.count("genesis-json") ) - { - fc::path genesis_json_filename = get_path( options, "genesis-json" ); - std::cerr << "embed_genesis: Reading genesis from file " << genesis_json_filename.preferred_string() << "\n"; - info.genesis_json = std::string(); - read_file_contents( genesis_json_filename, *info.genesis_json ); - } - else - info.genesis = graphene::app::detail::create_example_genesis(); - - if( options.count("chain-id") ) - { - std::string chain_id_str = options["chain-id"].as(); - std::cerr << "embed_genesis: Genesis ID from argument is " << chain_id_str << "\n"; - info.chain_id = chain_id_str; - } -} - -int main( int argc, char** argv ) -{ try { - int main_return = 0; - boost::program_options::options_description cli_options("Graphene Chain Identifier"); - cli_options.add_options() - ("help,h", "Print this help message and exit.") - ("genesis-json,g", boost::program_options::value(), "File to read genesis state from") - ("tmplsub,t", boost::program_options::value >()->composing(), - "Given argument of form src.cpp.tmpl---dest.cpp, write dest.cpp expanding template invocations in src") - ; - - boost::program_options::variables_map options; - try - { - boost::program_options::store( boost::program_options::parse_command_line(argc, argv, cli_options), options ); - } - catch (const boost::program_options::error& e) - { - std::cerr << "embed_genesis: error parsing command line: " << e.what() << "\n"; - return 1; - } - - if( options.count("help") ) - { - std::cout << cli_options << "\n"; - return 0; - } - - egenesis_info info; - - load_genesis( options, info ); - info.fillin(); - - fc::mutable_variant_object template_context = fc::mutable_variant_object() - ( "generated_file_banner", generated_file_banner ) - ( "chain_id", (*info.chain_id).str() ) - ; - if( info.genesis_json.valid() ) - { - template_context["genesis_json_length"] = info.genesis_json->length(); - template_context["genesis_json_array"] = (*info.genesis_json_array); - template_context["genesis_json_hash"] = (*info.genesis_json_hash).str(); - template_context["genesis_json_array_width"] = info.genesis_json_array_width; - template_context["genesis_json_array_height"] = info.genesis_json_array_height; - } - - for( const std::string& src_dest : options["tmplsub"].as< std::vector< std::string > >() ) - { - std::cerr << "embed_genesis: parsing tmplsub parameter \"" << src_dest << "\"\n"; - size_t pos = src_dest.find( "---" ); - if( pos == std::string::npos ) - { - std::cerr << "embed_genesis: could not parse tmplsub parameter: '---' not found\n"; - main_return = 1; - continue; - } - std::string src = src_dest.substr( 0, pos ); - std::string dest = src_dest.substr( pos+3 ); - - std::string tmpl; - read_file_contents( fc::path( src ), tmpl ); - std::string out_str = fc::format_string( tmpl, template_context ); - fc::path dest_filename = fc::path( dest ); - fc::ofstream outfile( dest_filename ); - outfile.write( out_str.c_str(), out_str.size() ); - outfile.close(); - } - - return main_return; -} FC_LOG_AND_RETHROW() } diff --git a/programs/build_helpers/CMakeLists.txt b/programs/build_helpers/CMakeLists.txt index 4ab1240e50..1f06923238 100644 --- a/programs/build_helpers/CMakeLists.txt +++ b/programs/build_helpers/CMakeLists.txt @@ -1,18 +1,9 @@ - -if( NOT(GRAPHENE_PREGENERATE_FILES) ) - add_executable( cat-parts cat-parts.cpp ) - if( UNIX AND NOT APPLE ) - set(rt_library rt ) - endif() - # we only actually need Boost, but link against FC for now so we don't duplicate it. - target_link_libraries( cat-parts PRIVATE fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) -endif( NOT(GRAPHENE_PREGENERATE_FILES) ) - add_executable( member_enumerator member_enumerator.cpp ) if( UNIX AND NOT APPLE ) - set(rt_library rt ) + set( rt_library rt ) endif() # we only actually need Boost, but link against FC for now so we don't duplicate it. -target_link_libraries( member_enumerator PRIVATE fc graphene_app graphene_net graphene_chain graphene_egenesis_brief graphene_utilities graphene_wallet ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) - +target_link_libraries( member_enumerator PRIVATE fc graphene_app graphene_net graphene_chain graphene_egenesis_brief + graphene_utilities graphene_wallet ${CMAKE_DL_LIBS} + ${PLATFORM_SPECIFIC_LIBS} ) diff --git a/programs/build_helpers/cat-parts.cpp b/programs/build_helpers/cat-parts.cpp deleted file mode 100644 index 13e692fea9..0000000000 --- a/programs/build_helpers/cat-parts.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -#include -#include - -#include -#include -#include -#include -#include - -int main( int argc, char** argv, char** envp ) -{ - if( argc != 3 ) - { - std::cerr << "syntax: cat-parts DIR OUTFILE" << std::endl; - return 1; - } - - boost::filesystem::path p(argv[1]); - - try - { - std::vector< boost::filesystem::path > v; - - for( boost::filesystem::directory_iterator it(p); - it != boost::filesystem::directory_iterator(); - ++it ) - { - boost::filesystem::path pit = it->path(); - std::string spit = pit.generic_string(); - size_t n = spit.length(); - if( n <= 3 ) - continue; - if( spit.substr(n-3, 3) != ".hf" ) - continue; - v.push_back( pit ); - } - std::sort( v.begin(), v.end() ); - - // open each file and grab its contents, concatenating into single stringstream - std::stringstream ss_data; - for( const boost::filesystem::path& p : v ) - { - boost::filesystem::ifstream ifs(p); - ss_data << ifs.rdbuf(); - } - std::string new_data = ss_data.str(); - - boost::filesystem::path opath(argv[2]); - - if( boost::filesystem::exists( opath ) ) - { - boost::filesystem::ifstream ifs(opath); - std::stringstream ss_old_data; - ss_old_data << ifs.rdbuf(); - std::string old_data = ss_old_data.str(); - if( old_data == new_data ) - { - std::cerr << "File " << opath << " up-to-date with .d directory" << std::endl; - return 0; - } - } - - { - boost::filesystem::create_directories(opath.parent_path()); - boost::filesystem::ofstream ofs(opath); - ofs.write( new_data.c_str(), new_data.length() ); - } - - std::cerr << "Built " << opath << " from .d directory" << std::endl; - } - catch( const boost::filesystem::filesystem_error& e ) - { - std::cout << e.what() << std::endl; - return 1; - } - return 0; -} From 0f505d4b51c209d6b4f3b756e3d334a25ba931b8 Mon Sep 17 00:00:00 2001 From: John Jones Date: Tue, 20 Aug 2019 10:58:45 -0500 Subject: [PATCH 031/534] Removed unnecessary reset of flags --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43f1dd40bc..337bd36ce7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,8 +94,6 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif () endif () -set(CMAKE_REQUIRED_FLAGS ${TEMP_REQUIRED_FLAGS} ) - # check for Data relocation and Protection (RELRO) set(CMAKE_REQUIRED_FLAGS "-Wl,-zrelro,-znow") check_c_compiler_flag("" HAVE_RELROFULL) From 26546965d8071296eaa40f03445c368f32ae1ba7 Mon Sep 17 00:00:00 2001 From: John Jones Date: Tue, 20 Aug 2019 15:01:38 -0500 Subject: [PATCH 032/534] Bump FC --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 91d8772b7b..1eebd3c692 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 91d8772b7b09819b59893d645d01fe181923693d +Subproject commit 1eebd3c69267d2867ba9299b5b5fe63fdc758d3f From 29270fe1da67caeee8bd934f03132645611e03ad Mon Sep 17 00:00:00 2001 From: manikey123 Date: Wed, 21 Aug 2019 00:13:14 -0700 Subject: [PATCH 033/534] updated database_api.cpp Change 2: Based on review comments to retain the previous code --- libraries/app/database_api.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 1cca257b45..40dd1718a5 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1213,14 +1213,7 @@ vector database_api_impl::get_collateral_bids( const std: collateral_bid_id_type(GRAPHENE_DB_MAX_INSTANCE_ID) ) ); vector result; auto distance_between_start_end= std::distance(start,end); - if(skip 0 && start != end ) { ++start; } while( start != end && limit-- > 0) { result.push_back(*start); From daf32ec17517ff1a54cc4318e58a1a13f42e9e8a Mon Sep 17 00:00:00 2001 From: manikey123 Date: Wed, 21 Aug 2019 00:39:27 -0700 Subject: [PATCH 034/534] updated database_api.cpp removed unused variables --- libraries/app/database_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 40dd1718a5..adbe87fc7f 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1212,7 +1212,6 @@ vector database_api_impl::get_collateral_bids( const std: price::min(back.id, asset_id), collateral_bid_id_type(GRAPHENE_DB_MAX_INSTANCE_ID) ) ); vector result; - auto distance_between_start_end= std::distance(start,end); while( skip-- > 0 && start != end ) { ++start; } while( start != end && limit-- > 0) { From 26cebe7eaf8312d63152335c914fe0546385525c Mon Sep 17 00:00:00 2001 From: crypto-ape <43807588+crypto-ape@users.noreply.github.com> Date: Tue, 13 Aug 2019 17:50:40 +0200 Subject: [PATCH 035/534] support openbsd // make code buildable --- CMakeLists.txt | 12 +++++++++--- libraries/net/node.cpp | 2 ++ tests/cli/main.cpp | 3 ++- tests/performance/performance_tests.cpp | 17 ++++++++--------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fd6a11bca..b49b7529ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,13 +216,19 @@ else( WIN32 ) # Apple AND Linux message( STATUS "Configuring BitShares on OS X" ) set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -stdlib=libc++ -Wall" ) else( APPLE ) - # Linux Specific Options Here - message( STATUS "Configuring BitShares on Linux" ) + if ( "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" ) + # OpenBSD Specific Options + message( STATUS "Configuring BitShares on OpenBSD" ) + else() + # Linux Specific Options Here + message( STATUS "Configuring BitShares on Linux" ) + set( rt_library rt ) + endif() + # Common Linux & OpenBSD Options set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall" ) if(USE_PROFILER) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg" ) endif( USE_PROFILER ) - set( rt_library rt ) set( pthread_library pthread) if ( NOT DEFINED crypto_library ) # I'm not sure why this is here, I guess someone has openssl and can't detect it with find_package()? diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 9a9b98386b..06aebf6fbd 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -1342,6 +1342,8 @@ namespace graphene { namespace net { namespace detail { user_data["fc_git_revision_unix_timestamp"] = fc::git_revision_unix_timestamp; #if defined( __APPLE__ ) user_data["platform"] = "osx"; +#elif defined( __OpenBSD__ ) + user_data["platform"] = "obsd"; #elif defined( __linux__ ) user_data["platform"] = "linux"; #elif defined( _MSC_VER ) diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index c2c0278a43..ccec5da7e9 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -49,9 +49,10 @@ #include #include #else + #include #include + #include #include - #include #endif #include diff --git a/tests/performance/performance_tests.cpp b/tests/performance/performance_tests.cpp index ae8a94fd77..152f672189 100644 --- a/tests/performance/performance_tests.cpp +++ b/tests/performance/performance_tests.cpp @@ -21,7 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include + +#include + +boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { + std::srand(time(NULL)); + std::cout << "Random number generator seeded to " << time(NULL) << std::endl; + return nullptr; +} #include @@ -208,11 +215,3 @@ BOOST_AUTO_TEST_CASE( one_hundred_k_benchmark ) } FC_LOG_AND_RETHROW() } BOOST_AUTO_TEST_SUITE_END() - -#include - -boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { - std::srand(time(NULL)); - std::cout << "Random number generator seeded to " << time(NULL) << std::endl; - return nullptr; -} From 318aba2c066b1d8c15be00b1c5d46483521ce0aa Mon Sep 17 00:00:00 2001 From: crypto-ape <43807588+crypto-ape@users.noreply.github.com> Date: Wed, 21 Aug 2019 16:35:49 +0200 Subject: [PATCH 036/534] Build scripts using CMake --- libraries/chain/CMakeLists.txt | 22 ++++++++-------- libraries/egenesis/CMakeLists.txt | 35 +++++++++++--------------- libraries/egenesis/embed_genesis.cmake | 24 ++++++++++++++++++ programs/build_helpers/CMakeLists.txt | 20 +++++++++++++++ programs/build_helpers/cat-parts.cmake | 31 +++++++++++++++++++++++ 5 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 libraries/egenesis/embed_genesis.cmake create mode 100644 programs/build_helpers/cat-parts.cmake diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 8679fe83a4..3852b82206 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -69,18 +69,7 @@ add_library( graphene_chain "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) -message( STATUS "Generating hardfork.hpp" ) -file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/" ) -file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tmp/" ) -file( REMOVE "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) -file( GLOB HARDFORKS "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d/*" ) -foreach( HF ${HARDFORKS} ) - file( READ "${HF}" INCL ) - file( APPEND "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" "${INCL}" ) - get_filename_component( _HF "${HF}" NAME ) - configure_file( "${HF}" "${CMAKE_CURRENT_BINARY_DIR}/tmp/${_HF}.tmp") -endforeach( HF ) - +add_dependencies( graphene_chain build_hardfork_hpp ) target_link_libraries( graphene_chain fc graphene_db graphene_protocol ) target_include_directories( graphene_chain PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" ) @@ -89,6 +78,15 @@ if(MSVC) set_source_files_properties( db_init.cpp db_block.cpp database.cpp block_database.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) +# Support for CMake < 3.7 +if (${CMAKE_VERSION} VERSION_LESS "3.7.0") + MESSAGE(STATUS "Configuring for legacy CMake (CMake version ${CMAKE_VERSION} older than 3.7.0)") + MESSAGE(STATUS " Target propertes not supported (SOURCE_DIR, BINARY_DIR)") + + set(GRAPHENE_CHAIN_BIN_LEGACY "${PROJECT_BINARY_DIR}") + set(GRAPHENE_CHAIN_SOURCE_LEGACY "${PROJECT_SOURCE_DIR}") +endif () + INSTALL( TARGETS graphene_chain diff --git a/libraries/egenesis/CMakeLists.txt b/libraries/egenesis/CMakeLists.txt index 74549d8817..9b208974d5 100644 --- a/libraries/egenesis/CMakeLists.txt +++ b/libraries/egenesis/CMakeLists.txt @@ -6,26 +6,21 @@ else( GRAPHENE_EGENESIS_JSON ) set( embed_genesis_args "genesis.json" ) endif( GRAPHENE_EGENESIS_JSON ) -file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tmp/" ) -configure_file( "${embed_genesis_args}" - "${CMAKE_CURRENT_BINARY_DIR}/tmp/genesis" ) - -file( SHA256 "${embed_genesis_args}" chain_id ) -set( generated_file_banner "/*** GENERATED FILE - DO NOT EDIT! ***/" ) -set( genesis_json_hash "${chain_id}" ) -configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" ) - -file( READ "${embed_genesis_args}" genesis_json ) -string( LENGTH "${genesis_json}" genesis_json_length ) -string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) -string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) -string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) -set( genesis_json_array "\"${genesis_json_escaped}\"" ) -set( genesis_json_array_height 1 ) -set( genesis_json_array_width ${genesis_json_length} ) -configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" - "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) +add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} + -DINIT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} + -DINIT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -Dembed_genesis_args=${embed_genesis_args} + -P ${CMAKE_CURRENT_SOURCE_DIR}/embed_genesis.cmake + DEPENDS + "${GRAPHENE_EGENESIS_JSON}" + "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" + "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" +) add_library( graphene_egenesis_none egenesis_none.cpp include/graphene/egenesis/egenesis.hpp ) diff --git a/libraries/egenesis/embed_genesis.cmake b/libraries/egenesis/embed_genesis.cmake new file mode 100644 index 0000000000..8313db2e5c --- /dev/null +++ b/libraries/egenesis/embed_genesis.cmake @@ -0,0 +1,24 @@ +set( CMAKE_CURRENT_SOURCE_DIR ${INIT_SOURCE_DIR} ) +set( CMAKE_CURRENT_BINARY_DIR ${INIT_BINARY_DIR} ) + +file( SHA256 "${embed_genesis_args}" chain_id ) +message( STATUS "Generating egenesis" ) + +message( STATUS "Chain-id: ${chain_id}" ) + +set( generated_file_banner "/*** GENERATED FILE - DO NOT EDIT! ***/" ) +set( genesis_json_hash "${chain_id}" ) +configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_brief.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_brief.cpp" ) + +file( READ "${embed_genesis_args}" genesis_json ) +string( LENGTH "${genesis_json}" genesis_json_length ) +string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) +string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) +string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) +set( genesis_json_array "\"${genesis_json_escaped}\"" ) +set( genesis_json_array_height 1 ) +set( genesis_json_array_width ${genesis_json_length} ) + +configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" + "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) diff --git a/programs/build_helpers/CMakeLists.txt b/programs/build_helpers/CMakeLists.txt index 1f06923238..23cb5e3a71 100644 --- a/programs/build_helpers/CMakeLists.txt +++ b/programs/build_helpers/CMakeLists.txt @@ -1,3 +1,23 @@ +get_target_property(GRAPHENE_CHAIN_SOURCE graphene_chain SOURCE_DIR) +get_target_property(GRAPHENE_CHAIN_BIN graphene_chain BINARY_DIR) + +# This is here only to support CMake < 3.7 +if (NOT GRAPHENE_CHAIN_SOURCE) + set(GRAPHENE_CHAIN_SOURCE ${GRAPHENE_CHAIN_SOURCE_LEGACY}) +endif() +# This is here only to support CMake < 3.7 +if (NOT GRAPHENE_CHAIN_BIN) + set(GRAPHENE_CHAIN_BIN ${GRAPHENE_CHAIN_BIN_LEGACY}) +endif() + +add_custom_target( build_hardfork_hpp + COMMAND + ${CMAKE_COMMAND} + -DINIT_BINARY_DIR=${GRAPHENE_CHAIN_BIN} + -DINIT_SOURCE_DIR=${GRAPHENE_CHAIN_SOURCE} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cat-parts.cmake +) + add_executable( member_enumerator member_enumerator.cpp ) if( UNIX AND NOT APPLE ) set( rt_library rt ) diff --git a/programs/build_helpers/cat-parts.cmake b/programs/build_helpers/cat-parts.cmake new file mode 100644 index 0000000000..dd49fbaec2 --- /dev/null +++ b/programs/build_helpers/cat-parts.cmake @@ -0,0 +1,31 @@ +message( STATUS "Generating hardfork.hpp" ) + +set( CMAKE_CURRENT_SOURCE_DIR ${INIT_SOURCE_DIR} ) +set( CMAKE_CURRENT_BINARY_DIR ${INIT_BINARY_DIR} ) + +set( HARDFORK_FILE "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/hardfork.hpp" ) +set( HARDFORK_CONTENT "" ) + +file( MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/graphene/chain/" ) + +set( HARDFORK_REGENERATE TRUE ) + +file( GLOB HARDFORKS "${CMAKE_CURRENT_SOURCE_DIR}/hardfork.d/*" ) +foreach( HF ${HARDFORKS} ) + file( READ "${HF}" INCL ) + string( CONCAT HARDFORK_CONTENT ${HARDFORK_CONTENT} ${INCL} ) +endforeach( HF ) + +if( EXISTS ${HARDFORK_FILE} ) + file( READ ${HARDFORK_FILE} HFF ) + + if( ${HFF} STREQUAL ${HARDFORK_CONTENT} ) + set( HARDFORK_REGENERATE FALSE ) + endif( ${HFF} STREQUAL ${HARDFORK_CONTENT} ) +endif( EXISTS ${HARDFORK_FILE} ) + +if( HARDFORK_REGENERATE ) + file( WRITE ${HARDFORK_FILE} ${HARDFORK_CONTENT} ) +else( HARDFORK_REGENERATE ) + message( STATUS "hardfork.hpp did not change" ) +endif( HARDFORK_REGENERATE ) From c956ff0edc08760d9709865c132acae52702f0ae Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 22 Aug 2019 18:51:29 -0300 Subject: [PATCH 037/534] remove newline doubles --- tests/tests/history_api_tests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/tests/history_api_tests.cpp b/tests/tests/history_api_tests.cpp index 53e426ca6c..e8856fda28 100644 --- a/tests/tests/history_api_tests.cpp +++ b/tests/tests/history_api_tests.cpp @@ -46,7 +46,6 @@ BOOST_AUTO_TEST_CASE(get_account_history) { create_account("dan"); create_account("bob"); - generate_block(); fc::usleep(fc::milliseconds(2000)); @@ -66,7 +65,6 @@ BOOST_AUTO_TEST_CASE(get_account_history) { BOOST_CHECK(histories[0].id.instance() != 0); BOOST_CHECK_EQUAL(histories[0].op.which(), account_create_op_id); - // Limit 2 returns 2 result histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 2, operation_history_id_type()); BOOST_CHECK_EQUAL(histories.size(), 2u); @@ -77,7 +75,6 @@ BOOST_AUTO_TEST_CASE(get_account_history) { BOOST_CHECK_EQUAL(histories.size(), 1u); BOOST_CHECK_EQUAL(histories[0].op.which(), account_create_op_id); - } catch (fc::exception &e) { edump((e.to_detail_string())); throw; From 7e599107d8ee82c4f438a2aef2b349c6ed7507eb Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 23 Aug 2019 14:41:25 -0300 Subject: [PATCH 038/534] implement storage_map and account_list --- libraries/app/api.cpp | 10 + libraries/app/include/graphene/app/api.hpp | 9 + .../custom_operations/custom_evaluators.cpp | 97 +++- .../custom_operations/custom_operations.cpp | 13 + .../custom_operations_plugin.cpp | 1 + .../custom_operations/custom_evaluators.hpp | 2 + .../custom_operations/custom_objects.hpp | 32 +- .../custom_operations/custom_operations.hpp | 38 ++ .../custom_operations_plugin.hpp | 6 +- tests/common/database_fixture.cpp | 4 +- tests/custom_operations/main.cpp | 439 ++++++++++++++++++ 11 files changed, 630 insertions(+), 21 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index a6aa07f126..83edac5c6f 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -738,4 +738,14 @@ namespace graphene { namespace app { return optional(); } + optional custom_operations_api::get_storage_info(std::string account_id_or_name)const + { + const auto account_id = database_api.get_account_id_from_string(account_id_or_name); + auto &index = _app.chain_database()->get_index_type().indices().get(); + auto itr = index.find(account_id); + if(itr != index.end()) + return *itr; + return optional(); + } + } } // graphene::app diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index f58582da4f..4650773d8d 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -571,6 +571,15 @@ namespace graphene { namespace app { */ optional get_htlc_offer(htlc_order_id_type id)const; + /** + * @breif Get storage information of an account + * + * @param account Account name to get info from + * + * @return The storage information of the account or empty + */ + optional get_storage_info(std::string account)const; + private: application& _app; graphene::app::database_api database_api; diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 1ce465c298..e409aa2369 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -35,6 +35,17 @@ custom_generic_evaluator::custom_generic_evaluator(database& db, const account_i _account = account; } +void fill_contact_object(account_contact_object& aco, account_id_type account, const account_contact_operation& op) +{ + aco.account = account; + if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; + if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; + if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; + if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; + if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; + if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; +} + object_id_type custom_generic_evaluator::do_apply(const account_contact_operation& op) { auto &index = _db->get_index_type().indices().get(); @@ -43,26 +54,14 @@ object_id_type custom_generic_evaluator::do_apply(const account_contact_operatio if( itr != index.end() ) { _db->modify( *itr, [&op, this]( account_contact_object& aco ){ - aco.account = _account; - if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; - if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; - if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; - if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; - if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; - if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; + fill_contact_object(aco, _account, op); }); return itr->id; } else { auto created = _db->create( [&op, this]( account_contact_object& aco ) { - aco.account = _account; - if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; - if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; - if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; - if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; - if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; - if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; + fill_contact_object(aco, _account, op); }); return created.id; } @@ -114,4 +113,74 @@ object_id_type custom_generic_evaluator::do_apply(const take_htlc_order_operatio return htlc_order_id; } +void fill_storage_map(account_storage_object& aso, account_id_type account, const account_store_data& op) +{ + aso.account = account; + if(op.extensions.value.pairs.valid()) + { + for(auto const& row: *op.extensions.value.pairs) { + if (op.extensions.value.remove.valid() && *op.extensions.value.remove) + aso.storage_map.erase(row.first); + else + aso.storage_map[row.first] = row.second; + } + } +} + +object_id_type custom_generic_evaluator::do_apply(const account_store_data& op) +{ + auto &index = _db->get_index_type().indices().get(); + + auto itr = index.find(_account); + if( itr != index.end() ) + { + _db->modify( *itr, [&op, this]( account_storage_object& aso ) { + fill_storage_map(aso, _account, op); + }); + return itr->id; + } + else + { + auto created = _db->create( [&op, this]( account_storage_object& aso ) { + fill_storage_map(aso, _account, op); + }); + return created.id; + } +} + +void fill_account_list(account_storage_object& aso, account_id_type account, const account_list_data& op) +{ + aso.account = account; + if(op.extensions.value.accounts.valid()) + { + for(auto const& account: *op.extensions.value.accounts) { + if (op.extensions.value.remove.valid() && *op.extensions.value.remove) + aso.account_list.erase(account); + else + aso.account_list.insert(account); + } + } +} + +object_id_type custom_generic_evaluator::do_apply(const account_list_data& op) +{ + auto &index = _db->get_index_type().indices().get(); + + auto itr = index.find(_account); + if( itr != index.end() ) + { + _db->modify( *itr, [&op, this]( account_storage_object& aso ) { + fill_account_list(aso, _account, op); + }); + return itr->id; + } + else + { + auto created = _db->create( [&op, this]( account_storage_object& aso ) { + fill_account_list(aso, _account, op); + }); + return created.id; + } +} + } } diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp index 673cb82d3b..54176a295d 100644 --- a/libraries/plugins/custom_operations/custom_operations.cpp +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -46,8 +46,21 @@ void take_htlc_order_operation::validate()const FC_ASSERT(extensions.value.htlc_order_id.valid()); } +void account_store_data::validate()const +{ + FC_ASSERT(extensions.value.pairs.valid()); + FC_ASSERT(extensions.value.pairs->size() <= 10); +} +void account_list_data::validate()const +{ + FC_ASSERT(extensions.value.accounts.valid()); + FC_ASSERT(extensions.value.accounts->size() <= 10); +} + } } //graphene::custom_operations GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_store_data ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_list_data ) diff --git a/libraries/plugins/custom_operations/custom_operations_plugin.cpp b/libraries/plugins/custom_operations/custom_operations_plugin.cpp index a8162d928d..9c6d3e169f 100644 --- a/libraries/plugins/custom_operations/custom_operations_plugin.cpp +++ b/libraries/plugins/custom_operations/custom_operations_plugin.cpp @@ -115,6 +115,7 @@ void custom_operations_plugin::plugin_initialize(const boost::program_options::v { database().add_index< primary_index< account_contact_index > >(); database().add_index< primary_index< htlc_orderbook_index > >(); + database().add_index< primary_index< account_storage_index > >(); database().applied_block.connect( [this]( const signed_block& b) { my->onBlock(b); diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp index 926df77eb8..7f11a967c2 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp @@ -37,6 +37,8 @@ class custom_generic_evaluator object_id_type do_apply(const account_contact_operation& o); object_id_type do_apply(const create_htlc_order_operation& o); object_id_type do_apply(const take_htlc_order_operation& o); + object_id_type do_apply(const account_store_data& o); + object_id_type do_apply(const account_list_data& o); }; } } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index 602a18f1c2..c92cda33d9 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -37,7 +37,9 @@ using namespace chain; enum types { account_contact = 0, create_htlc = 1, - take_htlc = 2 + take_htlc = 2, + account_store = 3, + account_list = 4 }; enum blockchains { eos = 0, @@ -83,6 +85,16 @@ struct htlc_order_object : public abstract_object optional close_time; }; +struct account_storage_object : public abstract_object +{ + static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; + static const uint8_t type_id = account_store; + + account_id_type account; + flat_map storage_map; + flat_set account_list; +}; + struct by_custom_id; struct by_custom_account; typedef multi_index_container< @@ -120,12 +132,23 @@ typedef multi_index_container< typedef generic_index htlc_orderbook_index; +typedef multi_index_container< + account_storage_object, + indexed_by< + ordered_non_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + member< account_storage_object, account_id_type, &account_storage_object::account > > + > +> account_storage_multi_index_type; + +typedef generic_index account_storage_index; + using account_contact_id_type = object_id; using htlc_order_id_type = object_id; +using account_storage_id_type = object_id; } } //graphene::custom_operations - FC_REFLECT_DERIVED( graphene::custom_operations::account_contact_object, (graphene::db::object), (account)(name)(email)(phone)(address)(company)(url)) FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::db::object), @@ -133,5 +156,8 @@ FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::d (blockchain_amount)(expiration)(order_time)(active) (blockchain_asset_precision)(token_contract)(tag)(taker_bitshares_account) (taker_blockchain_account)(close_time)) -FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc) ) +FC_REFLECT_DERIVED( graphene::custom_operations::account_storage_object, (graphene::db::object), + (account)(storage_map)(account_list)) +FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc)(account_store) + (account_list)) FC_REFLECT_ENUM( graphene::custom_operations::blockchains, (eos)(bitcoin)(ripple)(ethereum) ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp index c6c1a4916a..1a9155ff7e 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp @@ -82,6 +82,33 @@ struct take_htlc_order_operation : chain::base_operation void validate()const; }; +struct account_store_data : chain::base_operation +{ + struct ext + { + optional remove; + optional> pairs; + }; + + graphene::protocol::extension extensions; + + void validate()const; +}; + +struct account_list_data : chain::base_operation +{ + struct ext + { + optional remove; + optional> accounts; + }; + + graphene::protocol::extension extensions; + + void validate()const; +}; + + } } //graphene::custom_operations FC_REFLECT( graphene::custom_operations::account_contact_operation::ext, (name)(email)(phone)(address)(company)(url) ) @@ -98,6 +125,17 @@ FC_REFLECT( graphene::custom_operations::take_htlc_order_operation::ext, (htlc_o FC_REFLECT_TYPENAME( graphene::protocol::extension ) FC_REFLECT( graphene::custom_operations::take_htlc_order_operation, (extensions) ) +FC_REFLECT( graphene::custom_operations::account_store_data::ext, (pairs)(remove) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::account_store_data, (extensions) ) + +FC_REFLECT( graphene::custom_operations::account_list_data::ext, (accounts)(remove) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::account_list_data, (extensions) ) + GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_store_data ) +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_list_data ) + diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp index cec86e6611..b8612215b2 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -56,11 +56,12 @@ class custom_operations_plugin : public graphene::app::plugin std::unique_ptr my; }; - typedef fc::static_variant< account_contact_operation, create_htlc_order_operation, - take_htlc_order_operation + take_htlc_order_operation, + account_store_data, + account_list_data > custom_plugin_operation; struct custom_operation_wrapper { @@ -84,7 +85,6 @@ struct custom_op_visitor } }; - } } //graphene::custom_operations FC_REFLECT_TYPENAME( graphene::custom_operations::custom_plugin_operation ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index a4914d8bf7..f792a986f6 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -286,7 +286,9 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) ahiplugin->plugin_startup(); } - if(current_test_name == "custom_operations_account_contact_test" || current_test_name == "custom_operations_htlc_bitshares_eos_test") { + if(current_test_name == "custom_operations_account_contact_test" || + current_test_name == "custom_operations_htlc_bitshares_eos_test" || + current_test_name == "custom_operations_account_storage_test") { auto custom_operations_plugin = app.register_plugin(); custom_operations_plugin->plugin_set_app(&app); custom_operations_plugin->plugin_initialize(options); diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 3e910705e2..e2b5606d8a 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -465,5 +465,444 @@ catch (fc::exception &e) { throw; } } +BOOST_AUTO_TEST_CASE(custom_operations_account_storage_test) +{ +try { + ACTORS((nathan)(alice)(robert)(patty)); + + app.enable_plugin("custom_operations"); + custom_operations_api custom_operations_api(app); + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + enable_fees(); + signed_transaction trx; + set_expiration(db, trx); + + int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); + + transfer(committee_account, nathan_id, asset(init_balance)); + transfer(committee_account, alice_id, asset(init_balance)); + + // nathan adds arbitrary account data via custom operation, simulating some dapp settings in this case + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["language"] = "en"; + pairs["image_url"] = "http://some.image.url/img.jpg"; + + store.extensions.value.pairs = pairs; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // check nathan stored data with the api + account_storage_object storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); + + BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); + auto row1 = storage_results_nathan.storage_map.find("language"); + auto row2 = storage_results_nathan.storage_map.find("image_url"); + + BOOST_CHECK_EQUAL(row1->first, "language"); + BOOST_CHECK_EQUAL(row1->second, "en"); + BOOST_CHECK_EQUAL(row2->first, "image_url"); + BOOST_CHECK_EQUAL(row2->second, "http://some.image.url/img.jpg"); + + // add accounts to account list storage + { + custom_operation op; + account_list_data list; + account_list_data::ext data; + + flat_set accounts; + accounts.insert(alice_id); + accounts.insert(robert_id); + + list.extensions.value.accounts = accounts; + + auto packed = fc::raw::pack(list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // get the account list for nathan, check alice and robert are there + auto account_list_nathan = *custom_operations_api.get_storage_info("nathan"); + + BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); + BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 2 ); + auto itr = account_list_nathan.account_list.begin(); + BOOST_CHECK_EQUAL(itr->instance.value, alice_id.instance.value); + ++itr; + BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + + // add a value into account list already there + { + custom_operation op; + account_list_data list; + account_list_data::ext data; + + flat_set accounts; + accounts.insert(alice_id); + + list.extensions.value.accounts = accounts; + + auto packed = fc::raw::pack(list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // nothing changes + account_list_nathan = *custom_operations_api.get_storage_info("nathan"); + BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); + BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 2 ); + itr = account_list_nathan.account_list.begin(); + BOOST_CHECK_EQUAL(itr->instance.value, alice_id.instance.value); + ++itr; + BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + + // delete alice from the list + { + custom_operation op; + account_list_data list; + account_list_data::ext data; + + flat_set accounts; + accounts.insert(alice_id); + + list.extensions.value.accounts = accounts; + list.extensions.value.remove = true; + + auto packed = fc::raw::pack(list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // alice gone + account_list_nathan = *custom_operations_api.get_storage_info("nathan"); + BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); + BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 1 ); + itr = account_list_nathan.account_list.begin(); + BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + + // add and edit more stuff to the storage + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["image_url"] = "http://new.image.url/newimg.jpg"; + pairs["theme"] = "dark"; + + store.extensions.value.pairs = pairs; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // all good, image_url updated and theme added + storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); + BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); + row1 = storage_results_nathan.storage_map.find("language"); + row2 = storage_results_nathan.storage_map.find("image_url"); + auto row3 = storage_results_nathan.storage_map.find("theme"); + + BOOST_CHECK_EQUAL(row1->first, "language"); + BOOST_CHECK_EQUAL(row1->second, "en"); + BOOST_CHECK_EQUAL(row2->first, "image_url"); + BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(row3->first, "theme"); + BOOST_CHECK_EQUAL(row3->second, "dark"); + + // delete stuff from the storage + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["theme"] = "dark"; + + store.extensions.value.pairs = pairs; + store.extensions.value.remove = true; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // theme is removed from the storage + storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); + BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); + row1 = storage_results_nathan.storage_map.find("language"); + row2 = storage_results_nathan.storage_map.find("image_url"); + + BOOST_CHECK_EQUAL(row1->first, "language"); + BOOST_CHECK_EQUAL(row1->second, "en"); + BOOST_CHECK_EQUAL(row2->first, "image_url"); + BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); + + // delete stuff from that it is not there + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["nothere"] = "nothere"; + + store.extensions.value.pairs = pairs; + store.extensions.value.remove = true; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // nothing changes + storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); + BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); + row1 = storage_results_nathan.storage_map.find("language"); + row2 = storage_results_nathan.storage_map.find("image_url"); + + BOOST_CHECK_EQUAL(row1->first, "language"); + BOOST_CHECK_EQUAL(row1->second, "en"); + BOOST_CHECK_EQUAL(row2->first, "image_url"); + BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); + + // add more than 10 storage items in 1 operation is not allowed + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["key1"] = "value1"; + pairs["key2"] = "value2"; + pairs["key3"] = "value3"; + pairs["key4"] = "value4"; + pairs["key5"] = "value5"; + pairs["key6"] = "value6"; + pairs["key7"] = "value7"; + pairs["key8"] = "value8"; + pairs["key9"] = "value9"; + pairs["key10"] = "value10"; + pairs["key11"] = "value11"; + + store.extensions.value.pairs = pairs; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // add more than 10 accounts to the list in 1 operation is not allowed + { + custom_operation op; + account_list_data list; + account_list_data::ext data; + + flat_set accounts; + accounts.insert(account_id_type(0)); + accounts.insert(account_id_type(1)); + accounts.insert(account_id_type(2)); + accounts.insert(account_id_type(3)); + accounts.insert(account_id_type(4)); + accounts.insert(account_id_type(5)); + accounts.insert(account_id_type(6)); + accounts.insert(account_id_type(7)); + accounts.insert(account_id_type(8)); + accounts.insert(account_id_type(9)); + accounts.insert(account_id_type(10)); + + list.extensions.value.accounts = accounts; + list.extensions.value.remove = true; + + auto packed = fc::raw::pack(list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = nathan_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, nathan_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + // alice, duplicated keys in storage, only second value will be added + { + custom_operation op; + account_store_data store; + account_store_data::ext data; + + flat_map pairs; + pairs["key1"] = "value1"; + pairs["key1"] = "value2"; + + store.extensions.value.pairs = pairs; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + auto storage_results_alice = *custom_operations_api.get_storage_info("alice"); + BOOST_CHECK_EQUAL(storage_results_alice.account.instance.value, 17 ); + row1 = storage_results_alice.storage_map.find("key1"); + + BOOST_CHECK_EQUAL(row1->first, "key1"); + BOOST_CHECK_EQUAL(row1->second, "value2"); + + // duplicated accounts in the list, only 1 will be inserted + { + custom_operation op; + account_list_data list; + account_list_data::ext data; + + flat_set accounts; + accounts.insert(robert_id); + accounts.insert(robert_id); + + list.extensions.value.accounts = accounts; + + auto packed = fc::raw::pack(list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = alice_id; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx, ~0); + trx.clear(); + } + + generate_block(); + fc::usleep(fc::milliseconds(200)); + + auto account_list_alice = *custom_operations_api.get_storage_info("alice"); + BOOST_CHECK_EQUAL(account_list_alice.account.instance.value, 17 ); + BOOST_CHECK_EQUAL(account_list_alice.account_list.size(), 1 ); + itr = account_list_nathan.account_list.begin(); + BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + +} +catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; +} } + BOOST_AUTO_TEST_SUITE_END() From 126016946ab6a22a5780677cde2d67df3ea8620e Mon Sep 17 00:00:00 2001 From: Alfredo Date: Sat, 24 Aug 2019 10:55:09 -0300 Subject: [PATCH 039/534] change underlying storage object and operations --- libraries/app/api.cpp | 16 +- libraries/app/include/graphene/app/api.hpp | 7 +- .../custom_operations/custom_evaluators.cpp | 102 +++---- .../custom_operations/custom_operations.cpp | 18 +- .../custom_operations/custom_evaluators.hpp | 4 +- .../custom_operations/custom_objects.hpp | 44 ++- .../custom_operations/custom_operations.hpp | 27 +- .../custom_operations_plugin.hpp | 4 +- tests/custom_operations/main.cpp | 267 +++++++++--------- 9 files changed, 261 insertions(+), 228 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 83edac5c6f..483179710c 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -738,14 +738,18 @@ namespace graphene { namespace app { return optional(); } - optional custom_operations_api::get_storage_info(std::string account_id_or_name)const + vector custom_operations_api::get_storage_info(std::string account_id_or_name, + std::string catalog)const { const auto account_id = database_api.get_account_id_from_string(account_id_or_name); - auto &index = _app.chain_database()->get_index_type().indices().get(); - auto itr = index.find(account_id); - if(itr != index.end()) - return *itr; - return optional(); + vector results; + auto &index = _app.chain_database()->get_index_type().indices().get(); + auto itr = index.lower_bound(make_tuple(account_id, catalog)); + while(itr != index.end() && itr->account == account_id && itr->catalog == catalog) { + results.push_back(*itr); + ++itr; + } + return results; } } } // graphene::app diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 4650773d8d..7f39b8bfca 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -572,13 +572,14 @@ namespace graphene { namespace app { optional get_htlc_offer(htlc_order_id_type id)const; /** - * @breif Get storage information of an account + * @breif Get all stored objects of an account * * @param account Account name to get info from + * @param catalog Category classification * - * @return The storage information of the account or empty + * @return The vector of objects of the account or empty */ - optional get_storage_info(std::string account)const; + vector get_storage_info(std::string account, std::string catalog)const; private: application& _app; diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index e409aa2369..875e9019c7 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -113,73 +113,65 @@ object_id_type custom_generic_evaluator::do_apply(const take_htlc_order_operatio return htlc_order_id; } -void fill_storage_map(account_storage_object& aso, account_id_type account, const account_store_data& op) +object_id_type custom_generic_evaluator::do_apply(const account_storage_map& op) { - aso.account = account; - if(op.extensions.value.pairs.valid()) - { - for(auto const& row: *op.extensions.value.pairs) { - if (op.extensions.value.remove.valid() && *op.extensions.value.remove) - aso.storage_map.erase(row.first); - else - aso.storage_map[row.first] = row.second; - } - } -} + auto &index = _db->get_index_type().indices().get(); -object_id_type custom_generic_evaluator::do_apply(const account_store_data& op) -{ - auto &index = _db->get_index_type().indices().get(); - - auto itr = index.find(_account); - if( itr != index.end() ) + if (op.extensions.value.remove.valid() && *op.extensions.value.remove) { - _db->modify( *itr, [&op, this]( account_storage_object& aso ) { - fill_storage_map(aso, _account, op); - }); - return itr->id; - } - else - { - auto created = _db->create( [&op, this]( account_storage_object& aso ) { - fill_storage_map(aso, _account, op); - }); - return created.id; + for(auto const& row: *op.extensions.value.key_values) { + auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); + if(itr != index.end()) + _db->remove(*itr); + } } -} - -void fill_account_list(account_storage_object& aso, account_id_type account, const account_list_data& op) -{ - aso.account = account; - if(op.extensions.value.accounts.valid()) - { - for(auto const& account: *op.extensions.value.accounts) { - if (op.extensions.value.remove.valid() && *op.extensions.value.remove) - aso.account_list.erase(account); + else { + for(auto const& row: *op.extensions.value.key_values) { + auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); + if(itr == index.end()) + { + auto created = _db->create( [&op, this, &row]( account_storage_object& aso ) { + aso.catalog = *op.extensions.value.catalog; + aso.account = _account; + aso.key = row.first; + aso.value = row.second; + }); + } else - aso.account_list.insert(account); + { + _db->modify(*itr, [&op, this, &row](account_storage_object &aso) { + aso.value = row.second; + }); + } } } } - -object_id_type custom_generic_evaluator::do_apply(const account_list_data& op) +object_id_type custom_generic_evaluator::do_apply(const account_storage_list& op) { - auto &index = _db->get_index_type().indices().get(); + auto &index = _db->get_index_type().indices().get(); - auto itr = index.find(_account); - if( itr != index.end() ) + if (op.extensions.value.remove.valid() && *op.extensions.value.remove) { - _db->modify( *itr, [&op, this]( account_storage_object& aso ) { - fill_account_list(aso, _account, op); - }); - return itr->id; + for(auto const& list_value: *op.extensions.value.values) { + + auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); + if(itr != index.end()) + _db->remove(*itr); + } } - else - { - auto created = _db->create( [&op, this]( account_storage_object& aso ) { - fill_account_list(aso, _account, op); - }); - return created.id; + else { + + for(auto const& list_value: *op.extensions.value.values) { + auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); + if(itr == index.end()) + { + auto created = _db->create( [&op, this, &list_value]( account_storage_object& aso ) { + aso.catalog = *op.extensions.value.catalog; + aso.account = _account; + aso.value = list_value; + }); + } + } } } diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp index 54176a295d..80ab429dab 100644 --- a/libraries/plugins/custom_operations/custom_operations.cpp +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -46,15 +46,17 @@ void take_htlc_order_operation::validate()const FC_ASSERT(extensions.value.htlc_order_id.valid()); } -void account_store_data::validate()const +void account_storage_map::validate()const { - FC_ASSERT(extensions.value.pairs.valid()); - FC_ASSERT(extensions.value.pairs->size() <= 10); + FC_ASSERT(extensions.value.catalog.valid()); + FC_ASSERT(extensions.value.key_values.valid()); + FC_ASSERT(extensions.value.key_values->size() <= 10); } -void account_list_data::validate()const +void account_storage_list::validate()const { - FC_ASSERT(extensions.value.accounts.valid()); - FC_ASSERT(extensions.value.accounts->size() <= 10); + FC_ASSERT(extensions.value.catalog.valid()); + FC_ASSERT(extensions.value.values.valid()); + FC_ASSERT(extensions.value.values->size() <= 10); } } } //graphene::custom_operations @@ -62,5 +64,5 @@ void account_list_data::validate()const GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_store_data ) -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_list_data ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) +GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp index 7f11a967c2..32a36fdae0 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp @@ -37,8 +37,8 @@ class custom_generic_evaluator object_id_type do_apply(const account_contact_operation& o); object_id_type do_apply(const create_htlc_order_operation& o); object_id_type do_apply(const take_htlc_order_operation& o); - object_id_type do_apply(const account_store_data& o); - object_id_type do_apply(const account_list_data& o); + object_id_type do_apply(const account_storage_map& o); + object_id_type do_apply(const account_storage_list& o); }; } } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index c92cda33d9..a4ac2b5093 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -91,8 +91,9 @@ struct account_storage_object : public abstract_object static const uint8_t type_id = account_store; account_id_type account; - flat_map storage_map; - flat_set account_list; + string catalog; + optional key; + string value; }; struct by_custom_id; @@ -132,12 +133,45 @@ typedef multi_index_container< typedef generic_index htlc_orderbook_index; +struct by_account_catalog; +struct by_account_catalog_key; +struct by_account_catalog_value; +struct by_account_catalog_key_value; + typedef multi_index_container< account_storage_object, indexed_by< ordered_non_unique< tag, member< object, object_id_type, &object::id > >, - ordered_unique< tag, - member< account_storage_object, account_id_type, &account_storage_object::account > > + ordered_non_unique< tag, + member< account_storage_object, account_id_type, &account_storage_object::account > >, + ordered_non_unique< tag, + composite_key< account_storage_object, + member< account_storage_object, account_id_type, &account_storage_object::account >, + member< account_storage_object, string, &account_storage_object::catalog > + > + >, + ordered_non_unique< tag, + composite_key< account_storage_object, + member< account_storage_object, account_id_type, &account_storage_object::account >, + member< account_storage_object, string, &account_storage_object::catalog >, + member< account_storage_object, optional, &account_storage_object::key > + > + >, + ordered_unique< tag, + composite_key< account_storage_object, + member< account_storage_object, account_id_type, &account_storage_object::account >, + member< account_storage_object, string, &account_storage_object::catalog >, + member< account_storage_object, string, &account_storage_object::value > + > + >, + ordered_unique< tag, + composite_key< account_storage_object, + member< account_storage_object, account_id_type, &account_storage_object::account >, + member< account_storage_object, string, &account_storage_object::catalog >, + member< account_storage_object, optional, &account_storage_object::key >, + member< account_storage_object, string, &account_storage_object::value > + > + > > > account_storage_multi_index_type; @@ -157,7 +191,7 @@ FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::d (blockchain_asset_precision)(token_contract)(tag)(taker_bitshares_account) (taker_blockchain_account)(close_time)) FC_REFLECT_DERIVED( graphene::custom_operations::account_storage_object, (graphene::db::object), - (account)(storage_map)(account_list)) + (account)(catalog)(key)(value)) FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc)(account_store) (account_list)) FC_REFLECT_ENUM( graphene::custom_operations::blockchains, (eos)(bitcoin)(ripple)(ethereum) ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp index 1a9155ff7e..976302ce63 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp @@ -82,12 +82,13 @@ struct take_htlc_order_operation : chain::base_operation void validate()const; }; -struct account_store_data : chain::base_operation +struct account_storage_map : chain::base_operation { struct ext { optional remove; - optional> pairs; + optional catalog; + optional> key_values; }; graphene::protocol::extension extensions; @@ -95,12 +96,13 @@ struct account_store_data : chain::base_operation void validate()const; }; -struct account_list_data : chain::base_operation +struct account_storage_list : chain::base_operation { struct ext { optional remove; - optional> accounts; + optional catalog; + optional> values; }; graphene::protocol::extension extensions; @@ -125,17 +127,16 @@ FC_REFLECT( graphene::custom_operations::take_htlc_order_operation::ext, (htlc_o FC_REFLECT_TYPENAME( graphene::protocol::extension ) FC_REFLECT( graphene::custom_operations::take_htlc_order_operation, (extensions) ) -FC_REFLECT( graphene::custom_operations::account_store_data::ext, (pairs)(remove) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::account_store_data, (extensions) ) +FC_REFLECT( graphene::custom_operations::account_storage_map::ext, (remove)(catalog)(key_values) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::account_storage_map, (extensions) ) -FC_REFLECT( graphene::custom_operations::account_list_data::ext, (accounts)(remove) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::account_list_data, (extensions) ) +FC_REFLECT( graphene::custom_operations::account_storage_list::ext, (catalog)(values)(remove) ) +FC_REFLECT_TYPENAME( graphene::protocol::extension ) +FC_REFLECT( graphene::custom_operations::account_storage_list, (extensions) ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_store_data ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_list_data ) - +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) +GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp index b8612215b2..d9ee4cdf61 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -60,8 +60,8 @@ typedef fc::static_variant< account_contact_operation, create_htlc_order_operation, take_htlc_order_operation, - account_store_data, - account_list_data + account_storage_map, + account_storage_list > custom_plugin_operation; struct custom_operation_wrapper { diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index e2b5606d8a..3916b3af57 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -485,17 +485,18 @@ try { transfer(committee_account, nathan_id, asset(init_balance)); transfer(committee_account, alice_id, asset(init_balance)); - // nathan adds arbitrary account data via custom operation, simulating some dapp settings in this case + // nathan adds key-value data via custom operation to a settings catalog { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["language"] = "en"; pairs["image_url"] = "http://some.image.url/img.jpg"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; + store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -514,28 +515,27 @@ try { fc::usleep(fc::milliseconds(200)); // check nathan stored data with the api - account_storage_object storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); - - BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); - auto row1 = storage_results_nathan.storage_map.find("language"); - auto row2 = storage_results_nathan.storage_map.find("image_url"); - - BOOST_CHECK_EQUAL(row1->first, "language"); - BOOST_CHECK_EQUAL(row1->second, "en"); - BOOST_CHECK_EQUAL(row2->first, "image_url"); - BOOST_CHECK_EQUAL(row2->second, "http://some.image.url/img.jpg"); - - // add accounts to account list storage + vector storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://some.image.url/img.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); + + // nathan add a list of accounts to storage { custom_operation op; - account_list_data list; - account_list_data::ext data; + account_storage_list list; + account_storage_list::ext data; - flat_set accounts; - accounts.insert(alice_id); - accounts.insert(robert_id); + flat_set accounts; + accounts.insert(alice.name); + accounts.insert(robert.name); - list.extensions.value.accounts = accounts; + list.extensions.value.values = accounts; + list.extensions.value.catalog = "contact_list"; auto packed = fc::raw::pack(list); packed.insert(packed.begin(), types::account_list); @@ -554,25 +554,24 @@ try { fc::usleep(fc::milliseconds(200)); // get the account list for nathan, check alice and robert are there - auto account_list_nathan = *custom_operations_api.get_storage_info("nathan"); - - BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); - BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 2 ); - auto itr = account_list_nathan.account_list.begin(); - BOOST_CHECK_EQUAL(itr->instance.value, alice_id.instance.value); - ++itr; - BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, robert.name); // add a value into account list already there { custom_operation op; - account_list_data list; - account_list_data::ext data; + account_storage_list list; + account_storage_list::ext data; - flat_set accounts; - accounts.insert(alice_id); + flat_set accounts; + accounts.insert(alice.name); - list.extensions.value.accounts = accounts; + list.extensions.value.values = accounts; + list.extensions.value.catalog = "contact_list"; auto packed = fc::raw::pack(list); packed.insert(packed.begin(), types::account_list); @@ -591,25 +590,25 @@ try { fc::usleep(fc::milliseconds(200)); // nothing changes - account_list_nathan = *custom_operations_api.get_storage_info("nathan"); - BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); - BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 2 ); - itr = account_list_nathan.account_list.begin(); - BOOST_CHECK_EQUAL(itr->instance.value, alice_id.instance.value); - ++itr; - BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, robert.name); // delete alice from the list { custom_operation op; - account_list_data list; - account_list_data::ext data; + account_storage_list list; + account_storage_list::ext data; - flat_set accounts; - accounts.insert(alice_id); + flat_set accounts; + accounts.insert(alice.name); - list.extensions.value.accounts = accounts; + list.extensions.value.values = accounts; list.extensions.value.remove = true; + list.extensions.value.catalog = "contact_list"; auto packed = fc::raw::pack(list); packed.insert(packed.begin(), types::account_list); @@ -628,23 +627,23 @@ try { fc::usleep(fc::milliseconds(200)); // alice gone - account_list_nathan = *custom_operations_api.get_storage_info("nathan"); - BOOST_CHECK_EQUAL(account_list_nathan.account.instance.value, 16 ); - BOOST_CHECK_EQUAL(account_list_nathan.account_list.size(), 1 ); - itr = account_list_nathan.account_list.begin(); - BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 1 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, robert.name); // add and edit more stuff to the storage { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["image_url"] = "http://new.image.url/newimg.jpg"; pairs["theme"] = "dark"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; + store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -662,31 +661,30 @@ try { generate_block(); fc::usleep(fc::milliseconds(200)); - // all good, image_url updated and theme added - storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); - BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); - row1 = storage_results_nathan.storage_map.find("language"); - row2 = storage_results_nathan.storage_map.find("image_url"); - auto row3 = storage_results_nathan.storage_map.find("theme"); - - BOOST_CHECK_EQUAL(row1->first, "language"); - BOOST_CHECK_EQUAL(row1->second, "en"); - BOOST_CHECK_EQUAL(row2->first, "image_url"); - BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); - BOOST_CHECK_EQUAL(row3->first, "theme"); - BOOST_CHECK_EQUAL(row3->second, "dark"); + // check old and new stuff + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 3 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); + BOOST_CHECK_EQUAL(*storage_results_nathan[2].key, "theme"); + BOOST_CHECK_EQUAL(storage_results_nathan[2].value, "dark"); // delete stuff from the storage { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["theme"] = "dark"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; store.extensions.value.remove = true; + store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -705,27 +703,27 @@ try { fc::usleep(fc::milliseconds(200)); // theme is removed from the storage - storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); - BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); - row1 = storage_results_nathan.storage_map.find("language"); - row2 = storage_results_nathan.storage_map.find("image_url"); - - BOOST_CHECK_EQUAL(row1->first, "language"); - BOOST_CHECK_EQUAL(row1->second, "en"); - BOOST_CHECK_EQUAL(row2->first, "image_url"); - BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); - - // delete stuff from that it is not there + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); + + // delete stuff that it is not there { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["nothere"] = "nothere"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; store.extensions.value.remove = true; + store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -744,21 +742,20 @@ try { fc::usleep(fc::milliseconds(200)); // nothing changes - storage_results_nathan = *custom_operations_api.get_storage_info("nathan"); - BOOST_CHECK_EQUAL(storage_results_nathan.account.instance.value, 16 ); - row1 = storage_results_nathan.storage_map.find("language"); - row2 = storage_results_nathan.storage_map.find("image_url"); - - BOOST_CHECK_EQUAL(row1->first, "language"); - BOOST_CHECK_EQUAL(row1->second, "en"); - BOOST_CHECK_EQUAL(row2->first, "image_url"); - BOOST_CHECK_EQUAL(row2->second, "http://new.image.url/newimg.jpg"); + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); // add more than 10 storage items in 1 operation is not allowed { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["key1"] = "value1"; @@ -773,7 +770,8 @@ try { pairs["key10"] = "value10"; pairs["key11"] = "value11"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; + store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -794,23 +792,24 @@ try { // add more than 10 accounts to the list in 1 operation is not allowed { custom_operation op; - account_list_data list; - account_list_data::ext data; - - flat_set accounts; - accounts.insert(account_id_type(0)); - accounts.insert(account_id_type(1)); - accounts.insert(account_id_type(2)); - accounts.insert(account_id_type(3)); - accounts.insert(account_id_type(4)); - accounts.insert(account_id_type(5)); - accounts.insert(account_id_type(6)); - accounts.insert(account_id_type(7)); - accounts.insert(account_id_type(8)); - accounts.insert(account_id_type(9)); - accounts.insert(account_id_type(10)); - - list.extensions.value.accounts = accounts; + account_storage_list list; + account_storage_list::ext data; + + flat_set accounts; + accounts.insert("init0"); + accounts.insert("init1"); + accounts.insert("init2"); + accounts.insert("init3"); + accounts.insert("init4"); + accounts.insert("init5"); + accounts.insert("init6"); + accounts.insert("init7"); + accounts.insert("init8"); + accounts.insert("init9"); + accounts.insert("init10"); + + list.extensions.value.values = accounts; + list.extensions.value.catalog = "contact_list"; list.extensions.value.remove = true; auto packed = fc::raw::pack(list); @@ -832,14 +831,15 @@ try { // alice, duplicated keys in storage, only second value will be added { custom_operation op; - account_store_data store; - account_store_data::ext data; + account_storage_map store; + account_storage_map::ext data; flat_map pairs; pairs["key1"] = "value1"; pairs["key1"] = "value2"; - store.extensions.value.pairs = pairs; + store.extensions.value.key_values = pairs; + store.extensions.value.catalog = "random"; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_store); @@ -857,24 +857,24 @@ try { generate_block(); fc::usleep(fc::milliseconds(200)); - auto storage_results_alice = *custom_operations_api.get_storage_info("alice"); - BOOST_CHECK_EQUAL(storage_results_alice.account.instance.value, 17 ); - row1 = storage_results_alice.storage_map.find("key1"); - - BOOST_CHECK_EQUAL(row1->first, "key1"); - BOOST_CHECK_EQUAL(row1->second, "value2"); + vector storage_results_alice = custom_operations_api.get_storage_info("alice", "random"); + BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); + BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); + BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "key1"); + BOOST_CHECK_EQUAL(storage_results_alice[0].value, "value2"); // duplicated accounts in the list, only 1 will be inserted { custom_operation op; - account_list_data list; - account_list_data::ext data; + account_storage_list list; + account_storage_list::ext data; - flat_set accounts; - accounts.insert(robert_id); - accounts.insert(robert_id); + flat_set accounts; + accounts.insert(robert.name); + accounts.insert(robert.name); - list.extensions.value.accounts = accounts; + list.extensions.value.values = accounts; + list.extensions.value.catalog = "contact_list"; auto packed = fc::raw::pack(list); packed.insert(packed.begin(), types::account_list); @@ -892,11 +892,10 @@ try { generate_block(); fc::usleep(fc::milliseconds(200)); - auto account_list_alice = *custom_operations_api.get_storage_info("alice"); - BOOST_CHECK_EQUAL(account_list_alice.account.instance.value, 17 ); - BOOST_CHECK_EQUAL(account_list_alice.account_list.size(), 1 ); - itr = account_list_nathan.account_list.begin(); - BOOST_CHECK_EQUAL(itr->instance.value, robert_id.instance.value); + storage_results_alice = custom_operations_api.get_storage_info("alice", "contact_list"); + BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); + BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); + BOOST_CHECK_EQUAL(storage_results_alice[0].value, robert.name); } catch (fc::exception &e) { From 2ac5f09ee9cde769607510aa602322a1cd21a580 Mon Sep 17 00:00:00 2001 From: crypto-ape <43807588+crypto-ape@users.noreply.github.com> Date: Mon, 26 Aug 2019 16:13:39 +0200 Subject: [PATCH 040/534] purge build warnings --- libraries/chain/db_maint.cpp | 4 ++-- libraries/chain/vesting_balance_object.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index ea4dda3526..7618fda50b 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -439,7 +439,7 @@ void database::initialize_budget_record( fc::time_point_sec now, budget_record& // be able to use the entire reserve budget_u128 += ((uint64_t(1) << GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS) - 1); budget_u128 >>= GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS; - if( budget_u128 < reserve.value ) + if( budget_u128 < static_cast(reserve.value) ) rec.total_budget = share_type(static_cast(budget_u128)); else rec.total_budget = reserve; @@ -492,7 +492,7 @@ void database::process_budget() worker_budget_u128 /= 60*60*24; share_type worker_budget; - if( worker_budget_u128 >= available_funds.value ) + if( worker_budget_u128 >= static_cast(available_funds.value) ) worker_budget = available_funds; else worker_budget = static_cast(worker_budget_u128); diff --git a/libraries/chain/vesting_balance_object.cpp b/libraries/chain/vesting_balance_object.cpp index fd723a3e6b..6c3f65a16e 100644 --- a/libraries/chain/vesting_balance_object.cpp +++ b/libraries/chain/vesting_balance_object.cpp @@ -117,7 +117,7 @@ asset cdd_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx return asset(0, ctx.balance.asset_id); fc::uint128_t cs_earned = compute_coin_seconds_earned(ctx); fc::uint128_t withdraw_available = cs_earned / std::max(vesting_seconds, 1u); - assert(withdraw_available <= ctx.balance.amount.value); + assert(withdraw_available <= static_cast(ctx.balance.amount.value)); return asset(static_cast(withdraw_available), ctx.balance.asset_id); } From db36b54df3e2b784769e8021e0265a07a39f5c7f Mon Sep 17 00:00:00 2001 From: crypto-ape <43807588+crypto-ape@users.noreply.github.com> Date: Mon, 26 Aug 2019 16:15:23 +0200 Subject: [PATCH 041/534] correct test info message --- tests/tests/htlc_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/htlc_tests.cpp b/tests/tests/htlc_tests.cpp index fefdc546cd..fda3ab2fb9 100644 --- a/tests/tests/htlc_tests.cpp +++ b/tests/tests/htlc_tests.cpp @@ -93,7 +93,7 @@ try { // Alice puts a contract on the blockchain { graphene::chain::htlc_create_operation create_operation; - BOOST_TEST_MESSAGE("Alice (who has 100 coins, is transferring 2 coins to Bob"); + BOOST_TEST_MESSAGE("Alice (who has 100 coins, is transferring 3 coins to Bob"); create_operation.amount = graphene::chain::asset( 3 * GRAPHENE_BLOCKCHAIN_PRECISION ); create_operation.to = bob_id; create_operation.claim_period_seconds = 60; From 4b3c2d9863ef1b38e970e2bb4301f9da618e7fa9 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Mon, 26 Aug 2019 18:05:06 -0300 Subject: [PATCH 042/534] dont do genesis if _es_objects_start_es_after_block --- libraries/plugins/es_objects/es_objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/plugins/es_objects/es_objects.cpp b/libraries/plugins/es_objects/es_objects.cpp index c88237164e..1291e2d1e6 100644 --- a/libraries/plugins/es_objects/es_objects.cpp +++ b/libraries/plugins/es_objects/es_objects.cpp @@ -79,6 +79,7 @@ class es_objects_plugin_impl bool es_objects_plugin_impl::genesis() { + if(_es_objects_start_es_after_block > 0) return true; ilog("elasticsearch OBJECTS: inserting data from genesis"); From 3a57465259f32f0894fe578cf2c661de3de1fba0 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 28 Aug 2019 15:46:33 -0500 Subject: [PATCH 043/534] Replace improper static_variant operator overloads with comparators --- libraries/fc | 2 +- .../include/graphene/protocol/base.hpp | 2 +- .../graphene/protocol/fee_schedule.hpp | 26 ++++++------- tests/common/database_fixture.cpp | 2 +- tests/common/database_fixture.hpp | 2 +- tests/tests/bitasset_tests.cpp | 38 +++++++++---------- tests/tests/fee_tests.cpp | 14 +++---- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/libraries/fc b/libraries/fc index 1eebd3c692..9f7f1b4790 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 1eebd3c69267d2867ba9299b5b5fe63fdc758d3f +Subproject commit 9f7f1b479067ffe75e293b8e54aa13f7bd052b0a diff --git a/libraries/protocol/include/graphene/protocol/base.hpp b/libraries/protocol/include/graphene/protocol/base.hpp index fbdf39fb06..f7cb4ef594 100644 --- a/libraries/protocol/include/graphene/protocol/base.hpp +++ b/libraries/protocol/include/graphene/protocol/base.hpp @@ -117,7 +117,7 @@ namespace graphene { namespace protocol { * @note static_variant compares only the type tag and not the * content. */ - typedef flat_set extensions_type; + using extensions_type = future_extensions::flat_set_type; ///@} diff --git a/libraries/protocol/include/graphene/protocol/fee_schedule.hpp b/libraries/protocol/include/graphene/protocol/fee_schedule.hpp index 590ae840d5..9d867819ef 100644 --- a/libraries/protocol/include/graphene/protocol/fee_schedule.hpp +++ b/libraries/protocol/include/graphene/protocol/fee_schedule.hpp @@ -30,14 +30,14 @@ namespace graphene { namespace protocol { template struct transform_to_fee_parameters> { - typedef fc::static_variant< typename T::fee_parameters_type... > type; + using type = fc::static_variant< typename T::fee_parameters_type... >; }; - typedef transform_to_fee_parameters::type fee_parameters; + using fee_parameters = transform_to_fee_parameters::type; template class fee_helper { public: - const typename Operation::fee_parameters_type& cget(const flat_set& parameters)const + const typename Operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( typename Operation::fee_parameters_type() ); FC_ASSERT( itr != parameters.end() ); @@ -48,13 +48,13 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const account_create_operation::fee_parameters_type& cget(const flat_set& parameters)const + const account_create_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( account_create_operation::fee_parameters_type() ); FC_ASSERT( itr != parameters.end() ); return itr->get(); } - typename account_create_operation::fee_parameters_type& get(flat_set& parameters)const + typename account_create_operation::fee_parameters_type& get(fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( account_create_operation::fee_parameters_type() ); FC_ASSERT( itr != parameters.end() ); @@ -65,7 +65,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const bid_collateral_operation::fee_parameters_type& cget(const flat_set& parameters)const + const bid_collateral_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( bid_collateral_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -80,7 +80,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const asset_update_issuer_operation::fee_parameters_type& cget(const flat_set& parameters)const + const asset_update_issuer_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( asset_update_issuer_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -95,7 +95,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const asset_claim_pool_operation::fee_parameters_type& cget(const flat_set& parameters)const + const asset_claim_pool_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( asset_claim_pool_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -110,7 +110,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const htlc_create_operation::fee_parameters_type& cget(const flat_set& parameters)const + const htlc_create_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( htlc_create_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -124,7 +124,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const htlc_redeem_operation::fee_parameters_type& cget(const flat_set& parameters)const + const htlc_redeem_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( htlc_redeem_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -137,7 +137,7 @@ namespace graphene { namespace protocol { template<> class fee_helper { public: - const htlc_extend_operation::fee_parameters_type& cget(const flat_set& parameters)const + const htlc_extend_operation::fee_parameters_type& cget(const fee_parameters::flat_set_type& parameters)const { auto itr = parameters.find( htlc_extend_operation::fee_parameters_type() ); if ( itr != parameters.end() ) @@ -190,7 +190,7 @@ namespace graphene { namespace protocol { return fee_helper().get(parameters); } template - const bool exists()const + bool exists()const { auto itr = parameters.find(typename Operation::fee_parameters_type()); return itr != parameters.end(); @@ -199,7 +199,7 @@ namespace graphene { namespace protocol { /** * @note must be sorted by fee_parameters.which() and have no duplicates */ - flat_set parameters; + fee_parameters::flat_set_type parameters; uint32_t scale = GRAPHENE_100_PERCENT; ///< fee * scale / GRAPHENE_100_PERCENT private: static void set_fee_parameters(fee_schedule& sched); diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index f4f88100e1..c8bf3517d9 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -798,7 +798,7 @@ void database_fixture::issue_uia( account_id_type recipient_id, asset amount ) } void database_fixture::change_fees( - const flat_set< fee_parameters >& new_params, + const fee_parameters::flat_set_type& new_params, uint32_t new_scale /* = 0 */ ) { diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 136d25ea46..e626475fb0 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -353,7 +353,7 @@ struct database_fixture { * finish creating a block */ void enable_fees(); - void change_fees( const flat_set< fee_parameters >& new_params, uint32_t new_scale = 0 ); + void change_fees( const fee_parameters::flat_set_type& new_params, uint32_t new_scale = 0 ); void upgrade_to_lifetime_member( account_id_type account ); void upgrade_to_lifetime_member( const account_object& account ); void upgrade_to_annual_member( account_id_type account ); diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index 62bc8b943d..2c07857e76 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -648,7 +648,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // this should pass BOOST_TEST_MESSAGE( "Evaluating a good operation" ); - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // test with a market issued asset BOOST_TEST_MESSAGE( "Sending a non-bitasset." ); @@ -677,25 +677,25 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // back by self BOOST_TEST_MESSAGE( "Message should contain: op.new_options.short_backing_asset == asset_obj.get_id()" ); op.new_options.short_backing_asset = bit_usd_id; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.new_options.short_backing_asset = correct_asset_id; // prediction market with different precision BOOST_TEST_MESSAGE( "Message should contain: for a PM, asset_obj.precision != new_backing_asset.precision" ); op.asset_to_update = asset_objs.prediction; op.issuer = asset_objs.prediction(db).issuer; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.asset_to_update = bit_usd_id; op.issuer = asset_objs.bit_usd(db).issuer; // checking old backing asset instead of new backing asset BOOST_TEST_MESSAGE( "Message should contain: to be backed by an asset which is not market issued asset nor CORE" ); op.new_options.short_backing_asset = asset_objs.six_precision; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); BOOST_TEST_MESSAGE( "Message should contain: modified a blockchain-controlled market asset to be backed by an asset " "which is not backed by CORE" ); op.new_options.short_backing_asset = asset_objs.prediction; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.new_options.short_backing_asset = correct_asset_id; // CHILDUSER is a non-committee asset backed by PARENT which is backed by CORE @@ -707,15 +707,15 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) op.issuer = asset_objs.bit_parent(db).issuer; op.new_options.short_backing_asset = asset_objs.bit_usdbacked; // this should generate a warning in the log, but not fail. - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // changing the backing asset to a UIA should work BOOST_TEST_MESSAGE( "Switching to a backing asset that is a UIA should work. No warning should be produced." ); op.new_options.short_backing_asset = asset_objs.user_issued; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // A -> B -> C, change B to be backed by A (circular backing) BOOST_TEST_MESSAGE( "Message should contain: A cannot be backed by B which is backed by A." ); op.new_options.short_backing_asset = asset_objs.bit_child_bitasset; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.new_options.short_backing_asset = asset_objs.user_issued; BOOST_TEST_MESSAGE( "Message should contain: but this asset is a backing asset for a committee-issued asset." ); // CHILDCOMMITTEE is a committee asset backed by PARENT which is backed by CORE @@ -724,7 +724,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) create_bitasset( "CHILDCOMMITTEE", GRAPHENE_COMMITTEE_ACCOUNT, 100, charge_market_fee, 2, asset_objs.bit_parent ); // it should again work, generating 2 warnings in the log. 1 for the above, and 1 new one. - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.asset_to_update = asset_objs.bit_usd; op.issuer = asset_objs.bit_usd(db).issuer; op.new_options.short_backing_asset = correct_asset_id; @@ -738,7 +738,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) op.asset_to_update = asset_objs.bit_usdbacked2; op.issuer = asset_objs.bit_usdbacked2(db).issuer; op.new_options.short_backing_asset = asset_objs.bit_usdbacked; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // set everything to a more normal state op.asset_to_update = asset_objs.bit_usdbacked; op.issuer = asset_objs.bit_usd(db).issuer; @@ -748,25 +748,25 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) BOOST_TEST_MESSAGE( "Message should contain: op.new_options.feed_lifetime_sec <= chain_parameters.block_interval" ); const auto good_feed_lifetime = op.new_options.feed_lifetime_sec; op.new_options.feed_lifetime_sec = db.get_global_properties().parameters.block_interval; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); BOOST_TEST_MESSAGE( "Message should contain: op.new_options.feed_lifetime_sec <= chain_parameters.block_interval" ); op.new_options.feed_lifetime_sec = db.get_global_properties().parameters.block_interval - 1; // default interval > 1 - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.new_options.feed_lifetime_sec = good_feed_lifetime; // Force settlement delay must exceed block interval. BOOST_TEST_MESSAGE( "Message should contain: op.new_options.force_settlement_delay_sec <= chain_parameters.block_interval" ); const auto good_force_settlement_delay_sec = op.new_options.force_settlement_delay_sec; op.new_options.force_settlement_delay_sec = db.get_global_properties().parameters.block_interval; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); BOOST_TEST_MESSAGE( "Message should contain: op.new_options.force_settlement_delay_sec <= chain_parameters.block_interval" ); op.new_options.force_settlement_delay_sec = db.get_global_properties().parameters.block_interval - 1; // default interval > 1 - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); op.new_options.force_settlement_delay_sec = good_force_settlement_delay_sec; // this should pass BOOST_TEST_MESSAGE( "We should be all good again." ); - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); } /****** @@ -794,7 +794,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // this should pass BOOST_TEST_MESSAGE( "Evaluating a good operation" ); - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // test with a market issued asset BOOST_TEST_MESSAGE( "Sending a non-bitasset." ); @@ -853,13 +853,13 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // changing the backing asset to a UIA should work BOOST_TEST_MESSAGE( "Switching to a backing asset that is a UIA should work." ); op.new_options.short_backing_asset = asset_objs.user_issued; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); // A -> B -> C, change B to be backed by A (circular backing) BOOST_TEST_MESSAGE( "Check for circular backing. This should generate an exception" ); op.new_options.short_backing_asset = asset_objs.bit_child_bitasset; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "'A' backed by 'B' backed by 'A'" ); op.new_options.short_backing_asset = asset_objs.user_issued; - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); BOOST_TEST_MESSAGE( "Creating CHILDCOMMITTEE" ); // CHILDCOMMITTEE is a committee asset backed by PARENT which is backed by CORE // Cannot change PARENT's backing asset from CORE to something else because that will make CHILDCOMMITTEE @@ -907,7 +907,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // this should pass BOOST_TEST_MESSAGE( "We should be all good again." ); - BOOST_CHECK( evaluator.evaluate(op) == void_result() ); + BOOST_CHECK( evaluator.evaluate(op).is_type() ); } diff --git a/tests/tests/fee_tests.cpp b/tests/tests/fee_tests.cpp index 6051509424..4e509a5dbb 100644 --- a/tests/tests/fee_tests.cpp +++ b/tests/tests/fee_tests.cpp @@ -763,7 +763,7 @@ BOOST_AUTO_TEST_CASE( fee_refund_test ) // C++ -- The above commented out statement doesn't work, I don't know why // so we will use the following rather lengthy initialization instead { - flat_set< fee_parameters > new_fees; + fee_parameters::flat_set_type new_fees; { limit_order_create_operation::fee_parameters_type create_fee_params; create_fee_params.fee = order_create_fee; @@ -880,7 +880,7 @@ BOOST_AUTO_TEST_CASE( non_core_fee_refund_test ) generate_block( skip ); - flat_set< fee_parameters > new_fees; + fee_parameters::flat_set_type new_fees; { limit_order_create_operation::fee_parameters_type create_fee_params; create_fee_params.fee = order_create_fee; @@ -1266,7 +1266,7 @@ BOOST_AUTO_TEST_CASE( hf445_fee_refund_cross_test ) generate_block( skip ); - flat_set< fee_parameters > new_fees; + fee_parameters::flat_set_type new_fees; { limit_order_create_operation::fee_parameters_type create_fee_params; create_fee_params.fee = order_create_fee; @@ -1772,9 +1772,9 @@ BOOST_AUTO_TEST_CASE( bsip26_fee_refund_test ) generate_block( skip ); - flat_set< fee_parameters > new_fees; - flat_set< fee_parameters > new_fees1; - flat_set< fee_parameters > new_fees2; + fee_parameters::flat_set_type new_fees; + fee_parameters::flat_set_type new_fees1; + fee_parameters::flat_set_type new_fees2; { limit_order_create_operation::fee_parameters_type create_fee_params; create_fee_params.fee = order_create_fee; @@ -2329,7 +2329,7 @@ BOOST_AUTO_TEST_CASE( bsip26_fee_refund_cross_test ) generate_block( skip ); - flat_set< fee_parameters > new_fees; + fee_parameters::flat_set_type new_fees; { limit_order_create_operation::fee_parameters_type create_fee_params; create_fee_params.fee = order_create_fee; From 9c23a2bdb297e7ba39d27dfc0b84636cd3e594c6 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Wed, 28 Aug 2019 19:30:45 -0300 Subject: [PATCH 044/534] add general storage wallet calls --- libraries/app/include/graphene/app/api.hpp | 3 +- .../custom_operations/custom_objects.hpp | 8 +- .../wallet/include/graphene/wallet/wallet.hpp | 43 ++++++++++ libraries/wallet/wallet.cpp | 74 +++++++++++++++++ tests/cli/main.cpp | 80 +++++++++++++++++++ tests/custom_operations/main.cpp | 12 +-- 6 files changed, 209 insertions(+), 11 deletions(-) diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 7f39b8bfca..d0e97f76a0 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -572,7 +572,7 @@ namespace graphene { namespace app { optional get_htlc_offer(htlc_order_id_type id)const; /** - * @breif Get all stored objects of an account + * @breif Get all stored objects of an account in a particular catalog * * @param account Account name to get info from * @param catalog Category classification @@ -726,6 +726,7 @@ FC_API(graphene::app::custom_operations_api, (get_account_htlc_offers) (get_active_htlc_offers) (get_htlc_offer) + (get_storage_info) ) FC_API(graphene::app::login_api, (login) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index a4ac2b5093..fb24f3f9ae 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -38,7 +38,7 @@ enum types { account_contact = 0, create_htlc = 1, take_htlc = 2, - account_store = 3, + account_map = 3, account_list = 4 }; enum blockchains { @@ -88,7 +88,7 @@ struct htlc_order_object : public abstract_object struct account_storage_object : public abstract_object { static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; - static const uint8_t type_id = account_store; + static const uint8_t type_id = account_map; account_id_type account; string catalog; @@ -179,7 +179,7 @@ typedef generic_index using account_contact_id_type = object_id; using htlc_order_id_type = object_id; -using account_storage_id_type = object_id; +using account_storage_id_type = object_id; } } //graphene::custom_operations @@ -192,6 +192,6 @@ FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::d (taker_blockchain_account)(close_time)) FC_REFLECT_DERIVED( graphene::custom_operations::account_storage_object, (graphene::db::object), (account)(catalog)(key)(value)) -FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc)(account_store) +FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc)(account_map) (account_list)) FC_REFLECT_ENUM( graphene::custom_operations::blockchains, (eos)(bitcoin)(ripple)(ethereum) ) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 60196feb5b..229a5df7cf 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2071,6 +2071,7 @@ class wallet_api * * @return The signed transaction */ + signed_transaction take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast); /** @@ -2083,6 +2084,48 @@ class wallet_api * @return A list of \c htlc_order_object that are active and non expired in the selected blockchain. */ vector get_active_htlc_offers(uint16_t blockchain); + + /** + * Manage account storage map(key->value) by using the custom operations plugin. + * + * Each account can optionally add random information in the form of a key-value map + * to be retrieved by any interested party. + * + * @param account The account ID or name that we are adding additional information to. + * @param data Storage data to be added. \c account_storage_map::ext + * @param broadcast true if you wish to broadcast the transaction + * + * @return The signed transaction + */ + signed_transaction account_store_map(string account, account_storage_map::ext map, bool broadcast); + + /** + * Manage a accounts list(values)by using the custom operations plugin. + * + * Each account can optionally add and delete data from a dedicated list + * to be retrieved by any interested party. Can be used as a whitelist, address book, etc. + * + * @param account The account ID or name that we are adding additional information to. + * @param data List data to be added. \c account_storage_list::ext + * @param broadcast true if you wish to broadcast the transaction + * + * @return The signed transaction + */ + signed_transaction account_store_list(string account, account_storage_list::ext data, bool broadcast); + + /** + * Get \c account_storage_object of an account by using the custom operations plugin. + * + * Storage data added to the map with @ref account_store_map and list data added by + * @ref account_list_accounts will be returned. + * + * @param account Account ID or name to get contact data from. + * @param catalog The catalog to retrieve. + * + * @return An \c account_storage_object or empty. + */ + vector get_account_storage(string account, string catalog); + }; } } diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 20eced8820..f534c1806a 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2051,6 +2051,64 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) } + signed_transaction account_store_map(string account, account_storage_map::ext map, bool broadcast) + { + try + { + FC_ASSERT( !self.is_locked() ); + + account_id_type account_id = get_account(account).id; + + custom_operation op; + account_storage_map store; + store.extensions.value = map; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_map); + packed.insert(packed.begin(), 0xFF); + + op.payer = account_id; + op.data = packed; + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); + tx.validate(); + + return sign_transaction(tx, broadcast); + + } FC_CAPTURE_AND_RETHROW( (account)(map)(broadcast) ) + } + + signed_transaction account_store_list(string account, account_storage_list::ext list, bool broadcast) + { + try + { + FC_ASSERT( !self.is_locked() ); + + account_id_type account_id = get_account(account).id; + + custom_operation op; + account_storage_list store; + store.extensions.value = list; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = account_id; + op.data = packed; + + signed_transaction tx; + tx.operations.push_back(op); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); + tx.validate(); + + return sign_transaction(tx, broadcast); + + } FC_CAPTURE_AND_RETHROW( (account)(list)(broadcast) ) + } + vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) { try { fc::optional vbid = maybe_id( account_name ); @@ -5278,6 +5336,7 @@ order_book wallet_api::get_order_book( const string& base, const string& quote, return( my->_remote_db->get_order_book( base, quote, limit ) ); } +// custom operations signed_transaction wallet_api::set_contact_information(string account, account_contact_operation::ext data, bool broadcast) { @@ -5313,6 +5372,21 @@ vector wallet_api::get_active_htlc_offers(uint16_t blockchain return results; } +signed_transaction wallet_api::account_store_map(string account, account_storage_map::ext map, bool broadcast) +{ + return my->account_store_map(account, map, broadcast); +} + +signed_transaction wallet_api::account_store_list(string account, account_storage_list::ext list, bool broadcast) +{ + return my->account_store_list(account, list, broadcast); +} + +vector wallet_api::get_account_storage(string account, string catalog) +{ + return my->_custom_operations->get_storage_info(account, catalog); +} + signed_block_with_info::signed_block_with_info( const signed_block& block ) : signed_block( block ) { diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index 6b2e90d18f..226d9e1661 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1307,3 +1307,83 @@ BOOST_FIXTURE_TEST_CASE( htlc_orderbook, cli_fixture ) throw; } } + +/////////////////// +// Test the general storage by custom operations plugin +/////////////////// +BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) +{ + try { + // create the taker account + INVOKE(create_new_account); + + auto db = app1->chain_database(); + + BOOST_TEST_MESSAGE("Storing in a map."); + + flat_map pairs; + pairs["key1"] = "value1"; + pairs["key2"] = "value2"; + + account_storage_map::ext map; + + map.key_values = pairs; + map.catalog = "any"; + + con.wallet_api_ptr->account_store_map("nathan", map, true); + + BOOST_TEST_MESSAGE("The system is generating a block."); + BOOST_CHECK(generate_block(app1)); + + BOOST_TEST_MESSAGE("Get current map for nathan."); + auto nathan_map = con.wallet_api_ptr->get_account_storage("nathan", "any"); + + BOOST_CHECK_EQUAL(nathan_map[0].id.instance(), 0); + BOOST_CHECK_EQUAL(nathan_map[0].account.instance.value, 17); + BOOST_CHECK_EQUAL(nathan_map[0].catalog, "any"); + BOOST_CHECK_EQUAL(*nathan_map[0].key, "key1"); + BOOST_CHECK_EQUAL(nathan_map[0].value, "value1"); + BOOST_CHECK_EQUAL(nathan_map[1].id.instance(), 1); + BOOST_CHECK_EQUAL(nathan_map[1].account.instance.value, 17); + BOOST_CHECK_EQUAL(nathan_map[1].catalog, "any"); + BOOST_CHECK_EQUAL(*nathan_map[1].key, "key2"); + BOOST_CHECK_EQUAL(nathan_map[1].value, "value2"); + + BOOST_TEST_MESSAGE("Storing in a list."); + + flat_set favs; + favs.insert("chocolate"); + favs.insert("milk"); + favs.insert("banana"); + + account_storage_list::ext list; + + list.values = favs; + list.catalog = "favourites"; + + con.wallet_api_ptr->account_store_list("nathan", list, true); + + BOOST_TEST_MESSAGE("The system is generating a block."); + BOOST_CHECK(generate_block(app1)); + + BOOST_TEST_MESSAGE("Get current list for nathan."); + auto nathan_list = con.wallet_api_ptr->get_account_storage("nathan", "favourites"); + + BOOST_CHECK_EQUAL(nathan_list[0].id.instance(), 2); + BOOST_CHECK_EQUAL(nathan_list[0].account.instance.value, 17); + BOOST_CHECK_EQUAL(nathan_list[0].catalog, "favourites"); + BOOST_CHECK_EQUAL(nathan_list[0].value, "banana"); + BOOST_CHECK_EQUAL(nathan_list[1].id.instance(), 3); + BOOST_CHECK_EQUAL(nathan_list[1].account.instance.value, 17); + BOOST_CHECK_EQUAL(nathan_list[1].catalog, "favourites"); + BOOST_CHECK_EQUAL(nathan_list[1].value, "chocolate"); + BOOST_CHECK_EQUAL(nathan_list[2].id.instance(), 4); + BOOST_CHECK_EQUAL(nathan_list[2].account.instance.value, 17); + BOOST_CHECK_EQUAL(nathan_list[2].catalog, "favourites"); + BOOST_CHECK_EQUAL(nathan_list[2].value, "milk"); + + } catch( fc::exception& e ) { + edump((e.to_detail_string())); + throw; + } +} diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 3916b3af57..b671dcf291 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -499,7 +499,7 @@ try { store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = nathan_id; @@ -646,7 +646,7 @@ try { store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = nathan_id; @@ -687,7 +687,7 @@ try { store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = nathan_id; @@ -726,7 +726,7 @@ try { store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = nathan_id; @@ -774,7 +774,7 @@ try { store.extensions.value.catalog = "settings"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = nathan_id; @@ -842,7 +842,7 @@ try { store.extensions.value.catalog = "random"; auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_store); + packed.insert(packed.begin(), types::account_map); packed.insert(packed.begin(), 0xFF); op.payer = alice_id; From 729950f56be5eea74d27f243dc7e2de8c6838067 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Thu, 29 Aug 2019 16:48:48 -0300 Subject: [PATCH 045/534] remove witness plugin from cli test --- tests/cli/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index ccec5da7e9..a2892feaf0 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -125,7 +124,6 @@ std::shared_ptr start_application(fc::temp_directory app1->register_plugin(true); app1->register_plugin< graphene::market_history::market_history_plugin >(true); - app1->register_plugin< graphene::witness_plugin::witness_plugin >(true); app1->register_plugin< graphene::grouped_orders::grouped_orders_plugin>(true); app1->startup_plugins(); boost::program_options::variables_map cfg; From fec40dd44a49872f3010fcc401362c3abfbdd78e Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 30 Aug 2019 11:41:24 -0300 Subject: [PATCH 046/534] move check --- libraries/plugins/es_objects/es_objects.cpp | 54 ++++++++++----------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/libraries/plugins/es_objects/es_objects.cpp b/libraries/plugins/es_objects/es_objects.cpp index 1291e2d1e6..814a1539ed 100644 --- a/libraries/plugins/es_objects/es_objects.cpp +++ b/libraries/plugins/es_objects/es_objects.cpp @@ -79,8 +79,6 @@ class es_objects_plugin_impl bool es_objects_plugin_impl::genesis() { - if(_es_objects_start_es_after_block > 0) return true; - ilog("elasticsearch OBJECTS: inserting data from genesis"); graphene::chain::database &db = _self.database(); @@ -316,33 +314,6 @@ void es_objects_plugin::plugin_set_program_options( void es_objects_plugin::plugin_initialize(const boost::program_options::variables_map& options) { - database().applied_block.connect([this](const signed_block &b) { - if(b.block_num() == 1) { - if (!my->genesis()) - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error populating genesis data."); - } - }); - - database().new_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { - if(!my->index_database(ids, "create")) - { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error creating object from ES database, we are going to keep trying."); - } - }); - database().changed_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { - if(!my->index_database(ids, "update")) - { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error updating object from ES database, we are going to keep trying."); - } - }); - database().removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { - if(!my->index_database(ids, "delete")) - { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error deleting object from ES database, we are going to keep trying."); - } - }); - - if (options.count("es-objects-elasticsearch-url")) { my->_es_objects_elasticsearch_url = options["es-objects-elasticsearch-url"].as(); } @@ -382,6 +353,31 @@ void es_objects_plugin::plugin_initialize(const boost::program_options::variable if (options.count("es-objects-start-es-after-block")) { my->_es_objects_start_es_after_block = options["es-objects-start-es-after-block"].as(); } + + database().applied_block.connect([this](const signed_block &b) { + if(b.block_num() == 1 && my->_es_objects_start_es_after_block == 0) { + if (!my->genesis()) + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error populating genesis data."); + } + }); + database().new_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "create")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error creating object from ES database, we are going to keep trying."); + } + }); + database().changed_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "update")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error updating object from ES database, we are going to keep trying."); + } + }); + database().removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { + if(!my->index_database(ids, "delete")) + { + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error deleting object from ES database, we are going to keep trying."); + } + }); } void es_objects_plugin::plugin_startup() From b17ae6a497af8fdcf3ba4fbae3518c6b1a5cb491 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 30 Aug 2019 11:47:49 -0300 Subject: [PATCH 047/534] wrap plugin long lines --- libraries/plugins/es_objects/es_objects.cpp | 36 ++++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/libraries/plugins/es_objects/es_objects.cpp b/libraries/plugins/es_objects/es_objects.cpp index 814a1539ed..79b9f1cdba 100644 --- a/libraries/plugins/es_objects/es_objects.cpp +++ b/libraries/plugins/es_objects/es_objects.cpp @@ -295,19 +295,25 @@ void es_objects_plugin::plugin_set_program_options( ) { cli.add_options() - ("es-objects-elasticsearch-url", boost::program_options::value(), "Elasticsearch node url(http://localhost:9200/)") + ("es-objects-elasticsearch-url", boost::program_options::value(), + "Elasticsearch node url(http://localhost:9200/)") ("es-objects-auth", boost::program_options::value(), "Basic auth username:password('')") - ("es-objects-bulk-replay", boost::program_options::value(), "Number of bulk documents to index on replay(10000)") - ("es-objects-bulk-sync", boost::program_options::value(), "Number of bulk documents to index on a synchronized chain(100)") + ("es-objects-bulk-replay", boost::program_options::value(), + "Number of bulk documents to index on replay(10000)") + ("es-objects-bulk-sync", boost::program_options::value(), + "Number of bulk documents to index on a synchronized chain(100)") ("es-objects-proposals", boost::program_options::value(), "Store proposal objects(true)") ("es-objects-accounts", boost::program_options::value(), "Store account objects(true)") ("es-objects-assets", boost::program_options::value(), "Store asset objects(true)") ("es-objects-balances", boost::program_options::value(), "Store balances objects(true)") ("es-objects-limit-orders", boost::program_options::value(), "Store limit order objects(true)") ("es-objects-asset-bitasset", boost::program_options::value(), "Store feed data(true)") - ("es-objects-index-prefix", boost::program_options::value(), "Add a prefix to the index(objects-)") - ("es-objects-keep-only-current", boost::program_options::value(), "Keep only current state of the objects(true)") - ("es-objects-start-es-after-block", boost::program_options::value(), "Start doing ES job after block(0)") + ("es-objects-index-prefix", boost::program_options::value(), + "Add a prefix to the index(objects-)") + ("es-objects-keep-only-current", boost::program_options::value(), + "Keep only current state of the objects(true)") + ("es-objects-start-es-after-block", boost::program_options::value(), + "Start doing ES job after block(0)") ; cfg.add(cli); } @@ -360,22 +366,28 @@ void es_objects_plugin::plugin_initialize(const boost::program_options::variable FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error populating genesis data."); } }); - database().new_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + database().new_objects.connect([this]( const vector& ids, + const flat_set& impacted_accounts ) { if(!my->index_database(ids, "create")) { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error creating object from ES database, we are going to keep trying."); + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error creating object from ES database, we are going to keep trying."); } }); - database().changed_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + database().changed_objects.connect([this]( const vector& ids, + const flat_set& impacted_accounts ) { if(!my->index_database(ids, "update")) { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error updating object from ES database, we are going to keep trying."); + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error updating object from ES database, we are going to keep trying."); } }); - database().removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { + database().removed_objects.connect([this](const vector& ids, + const vector& objs, const flat_set& impacted_accounts) { if(!my->index_database(ids, "delete")) { - FC_THROW_EXCEPTION(graphene::chain::plugin_exception, "Error deleting object from ES database, we are going to keep trying."); + FC_THROW_EXCEPTION(graphene::chain::plugin_exception, + "Error deleting object from ES database, we are going to keep trying."); } }); } From 95787eef45c496246b857e433ca61f97de2ec30f Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sat, 31 Aug 2019 10:49:54 -0500 Subject: [PATCH 048/534] Bump FC --- libraries/fc | 2 +- .../protocol/include/graphene/protocol/types.hpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/fc b/libraries/fc index 9f7f1b4790..a75fcb56f3 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 9f7f1b479067ffe75e293b8e54aa13f7bd052b0a +Subproject commit a75fcb56f3cd51eb28d43673c9ea583fe23cfe34 diff --git a/libraries/protocol/include/graphene/protocol/types.hpp b/libraries/protocol/include/graphene/protocol/types.hpp index 0927fa1d87..7b1d2c0e83 100644 --- a/libraries/protocol/include/graphene/protocol/types.hpp +++ b/libraries/protocol/include/graphene/protocol/types.hpp @@ -77,9 +77,18 @@ namespace fc { \ template<> struct reflector {\ typedef TYPE type; \ typedef std::true_type is_defined; \ + using native_members = \ + typename typelist::builder<>::type \ + BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \ + using inherited_members = \ + typename typelist::builder<>::type \ + BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \ + using members = typename typelist::concat::type; \ + using base_classes = typename typelist::builder<>::type \ + BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \ enum member_count_enum { \ - local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ - total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ + local_member_count = typelist::length(), \ + total_member_count = typelist::length() \ }; \ FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ }; \ From 7d115b94a22f3f55ec52aaacd0587f03803d14cb Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sat, 31 Aug 2019 11:09:41 -0500 Subject: [PATCH 049/534] Fix warnings --- libraries/wallet/wallet.cpp | 2 +- tests/cli/main.cpp | 8 ++++---- tests/tests/database_api_tests.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index b96225702b..e35082f89c 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2738,7 +2738,7 @@ class wallet_api_impl return ss.str(); }; - m["sign_message"] = [this](variant result, const fc::variants& a) + m["sign_message"] = [](variant result, const fc::variants& a) { auto r = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index a2892feaf0..45a8eb3603 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1130,10 +1130,10 @@ BOOST_FIXTURE_TEST_CASE( cli_sign_message, cli_fixture ) // change account, verify failure msg.meta.account = "dan"; - BOOST_REQUIRE_THROW( !con.wallet_api_ptr->verify_message( msg.message, msg.meta.account, msg.meta.block, - msg.meta.time, *msg.signature ), fc::assert_exception ); - BOOST_REQUIRE_THROW( !con.wallet_api_ptr->verify_signed_message( msg ), fc::assert_exception ); - BOOST_REQUIRE_THROW( !con.wallet_api_ptr->verify_encapsulated_message( encapsulate( msg ) ), fc::assert_exception); + BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_message( msg.message, msg.meta.account, msg.meta.block, + msg.meta.time, *msg.signature ), fc::assert_exception ); + BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_signed_message( msg ), fc::assert_exception ); + BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_encapsulated_message( encapsulate( msg ) ), fc::assert_exception); msg.meta.account = "nathan"; // change key, verify failure diff --git a/tests/tests/database_api_tests.cpp b/tests/tests/database_api_tests.cpp index a577f7a281..31f03e7781 100644 --- a/tests/tests/database_api_tests.cpp +++ b/tests/tests/database_api_tests.cpp @@ -1958,7 +1958,7 @@ BOOST_AUTO_TEST_CASE(api_limit_get_collateral_bids) { // this sell order is designed to trigger a black swan - create_sell_order( borrower2_id(db), swan(db).amount(1), back(db).amount(3) )->id; + create_sell_order( borrower2_id(db), swan(db).amount(1), back(db).amount(3) ); BOOST_CHECK( swan(db).bitasset_data(db).has_settlement() ); //making 3 collateral bids for (int i=0; i<3; i++) { From 65eb08660196385e6a8263f4357020a028f4e6d9 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sat, 31 Aug 2019 15:55:02 -0500 Subject: [PATCH 050/534] Add test condition --- tests/cli/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index 45a8eb3603..43dfaabfb3 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1129,11 +1129,18 @@ BOOST_FIXTURE_TEST_CASE( cli_sign_message, cli_fixture ) msg.message = "123"; // change account, verify failure + // nonexistent account: msg.meta.account = "dan"; BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_message( msg.message, msg.meta.account, msg.meta.block, msg.meta.time, *msg.signature ), fc::assert_exception ); BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_signed_message( msg ), fc::assert_exception ); BOOST_REQUIRE_THROW( con.wallet_api_ptr->verify_encapsulated_message( encapsulate( msg ) ), fc::assert_exception); + // existing, but wrong account: + msg.meta.account = "committee-account"; + BOOST_CHECK( !con.wallet_api_ptr->verify_message( msg.message, msg.meta.account, msg.meta.block, + msg.meta.time, *msg.signature ) ); + BOOST_CHECK( !con.wallet_api_ptr->verify_signed_message( msg ) ); + BOOST_CHECK( !con.wallet_api_ptr->verify_encapsulated_message( encapsulate( msg ) ) ); msg.meta.account = "nathan"; // change key, verify failure From 33cb896d87a700836efb873985d09fac86edfb0f Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Sun, 1 Sep 2019 10:34:10 -0500 Subject: [PATCH 051/534] Bump FC --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index a75fcb56f3..4b7bcb951d 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit a75fcb56f3cd51eb28d43673c9ea583fe23cfe34 +Subproject commit 4b7bcb951d5c6fd8be95a3d92a8b84115ce0cdd4 From 938201ad6568c7c0d2bdf95291c488099aafd7aa Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Mon, 2 Sep 2019 09:54:11 -0500 Subject: [PATCH 052/534] Fix build --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 4b7bcb951d..7e69567dd0 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 4b7bcb951d5c6fd8be95a3d92a8b84115ce0cdd4 +Subproject commit 7e69567dd05525f83120f672d72a15118123d6de From 787f7e5a2b79161978b3eca7b2fa9657d9af3eee Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Mon, 2 Sep 2019 11:52:40 -0500 Subject: [PATCH 053/534] Move FC_REFLECT_DERIVED_NO_TYPENAME to FC --- libraries/fc | 2 +- .../include/graphene/protocol/types.hpp | 22 ------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/libraries/fc b/libraries/fc index 7e69567dd0..9db1417b25 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 7e69567dd05525f83120f672d72a15118123d6de +Subproject commit 9db1417b2529e7456226676f0c0ad1f09e2dd449 diff --git a/libraries/protocol/include/graphene/protocol/types.hpp b/libraries/protocol/include/graphene/protocol/types.hpp index 7b1d2c0e83..b861efc78a 100644 --- a/libraries/protocol/include/graphene/protocol/types.hpp +++ b/libraries/protocol/include/graphene/protocol/types.hpp @@ -72,28 +72,6 @@ namespace raw { \ #define GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION(type) GRAPHENE_EXTERNAL_SERIALIZATION(extern, type) #define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type) GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, type) -#define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \ -namespace fc { \ -template<> struct reflector {\ - typedef TYPE type; \ - typedef std::true_type is_defined; \ - using native_members = \ - typename typelist::builder<>::type \ - BOOST_PP_SEQ_FOR_EACH_I( FC_CONCAT_MEMBER_REFLECTION, TYPE, MEMBERS ) ::finalize; \ - using inherited_members = \ - typename typelist::builder<>::type \ - BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_BASE_MEMBER_REFLECTIONS, TYPE, INHERITS ) ::finalize; \ - using members = typename typelist::concat::type; \ - using base_classes = typename typelist::builder<>::type \ - BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \ - enum member_count_enum { \ - local_member_count = typelist::length(), \ - total_member_count = typelist::length() \ - }; \ - FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ -}; \ -} // fc - #define GRAPHENE_NAME_TO_OBJECT_TYPE(x, prefix, name) BOOST_PP_CAT(prefix, BOOST_PP_CAT(name, _object_type)) #define GRAPHENE_NAME_TO_ID_TYPE(x, y, name) BOOST_PP_CAT(name, _id_type) #define GRAPHENE_DECLARE_ID(x, space_prefix_seq, name) \ From 68f40d5733c3535bb355a04d5de1bd96cfd6f50e Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Wed, 4 Sep 2019 15:21:04 +0200 Subject: [PATCH 054/534] Split genesis into 10k chunks --- libraries/egenesis/egenesis_full.cpp.tmpl | 7 +++---- libraries/egenesis/embed_genesis.cmake | 16 +++++++++++++--- libraries/egenesis/test.json | 0 3 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 libraries/egenesis/test.json diff --git a/libraries/egenesis/egenesis_full.cpp.tmpl b/libraries/egenesis/egenesis_full.cpp.tmpl index 0aead4c823..75391348fd 100644 --- a/libraries/egenesis/egenesis_full.cpp.tmpl +++ b/libraries/egenesis/egenesis_full.cpp.tmpl @@ -30,7 +30,7 @@ namespace graphene { namespace egenesis { using namespace graphene::chain; -static const char genesis_json_array[${genesis_json_array_height}][${genesis_json_array_width}+1] = +static const char* genesis_json_array[${genesis_json_array_height}] = { ${genesis_json_array} }; @@ -44,11 +44,10 @@ void compute_egenesis_json( std::string& result ) { result.reserve( ${genesis_json_length} ); result.resize(0); - for( size_t i=0; i<${genesis_json_array_height}-1; i++ ) + for( size_t i=0; i<${genesis_json_array_height}; i++ ) { - result.append( genesis_json_array[i], ${genesis_json_array_width} ); + result.append( genesis_json_array[i] ); } - result.append( std::string( genesis_json_array[ ${genesis_json_array_height}-1 ] ) ); } fc::sha256 get_egenesis_json_hash() diff --git a/libraries/egenesis/embed_genesis.cmake b/libraries/egenesis/embed_genesis.cmake index 8313db2e5c..9691b5beb2 100644 --- a/libraries/egenesis/embed_genesis.cmake +++ b/libraries/egenesis/embed_genesis.cmake @@ -16,9 +16,19 @@ string( LENGTH "${genesis_json}" genesis_json_length ) string( REGEX REPLACE "(\"|\\\\)" "\\\\\\1" genesis_json_escaped "${genesis_json}" ) string( REPLACE "\n" "\\n" genesis_json_escaped "${genesis_json_escaped}" ) string( REPLACE "\t" "\\t" genesis_json_escaped "${genesis_json_escaped}" ) -set( genesis_json_array "\"${genesis_json_escaped}\"" ) -set( genesis_json_array_height 1 ) -set( genesis_json_array_width ${genesis_json_length} ) + +# Split the escaped JSON string into chunks (each less than max string literal length supported by MSVC). +# Chunks must not end with a backslash to avoid splitting escapes. +string( RANDOM LENGTH 10000 _dots ) +string( REGEX REPLACE "." "." _dots "${_dots}" ) +string( REGEX MATCHALL "(${_dots}(.|..|...)?[^\\\\])" _chunks "${genesis_json_escaped}" ) +string( LENGTH "${_chunks}" _chunks_len ) +string( REGEX REPLACE ";" "" _seen "${_chunks}" ) +string( LENGTH "${_seen}" _seen ) +string( SUBSTRING "${genesis_json_escaped}" ${_seen} -1 _rest ) +string( REGEX REPLACE ";" "\",\n\"" genesis_json_array "${_chunks}" ) +set( genesis_json_array "\"${genesis_json_array}\",\n\"${_rest}\"" ) +set( genesis_json_array_height "${_chunks_len} - ${_seen} + 2" ) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/egenesis_full.cpp.tmpl" "${CMAKE_CURRENT_BINARY_DIR}/egenesis_full.cpp" ) diff --git a/libraries/egenesis/test.json b/libraries/egenesis/test.json new file mode 100644 index 0000000000..e69de29bb2 From c94dbd39ba2b800f20425e070ad9d800d0bfa318 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Fri, 6 Sep 2019 21:26:16 +0200 Subject: [PATCH 055/534] Use appropriate static/dynamic openssl libs for curl --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b32dcc2f5b..d83d4bf23f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,8 @@ macro(FIND_CURL) set (OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set (CMAKE_FIND_LIBRARY_SUFFIXES .a) find_package(CURL REQUIRED) - list(APPEND CURL_LIBRARIES ssl crypto) + find_package(OpenSSL REQUIRED) + list(APPEND CURL_LIBRARIES ${OPENSSL_LIBRARIES} ${BOOST_THREAD_LIBRARY} ${CMAKE_DL_LIBS}) set (CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) else (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) find_package(CURL REQUIRED) From 3e3318779b2e1368741850136101aff6bcf5fb17 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Sat, 7 Sep 2019 10:07:07 +0200 Subject: [PATCH 056/534] Make sure openssl looks not only for static libs --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d83d4bf23f..cc5f9b6a48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,10 +38,10 @@ include(Utils) # function to help with cUrl macro(FIND_CURL) if (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) + find_package(OpenSSL REQUIRED) set (OLD_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) set (CMAKE_FIND_LIBRARY_SUFFIXES .a) find_package(CURL REQUIRED) - find_package(OpenSSL REQUIRED) list(APPEND CURL_LIBRARIES ${OPENSSL_LIBRARIES} ${BOOST_THREAD_LIBRARY} ${CMAKE_DL_LIBS}) set (CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_SUFFIXES}) else (NOT WIN32 AND NOT APPLE AND CURL_STATICLIB) From e4f0d762339ebd01216e2cca17a2af31bd59822a Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Tue, 10 Sep 2019 18:51:46 -0300 Subject: [PATCH 057/534] leave only general storage code --- libraries/app/api.cpp | 51 - libraries/app/include/graphene/app/api.hpp | 46 +- .../custom_operations/custom_evaluators.cpp | 150 +-- .../custom_operations/custom_operations.cpp | 26 +- .../custom_operations_plugin.cpp | 2 - .../custom_operations/custom_evaluators.hpp | 7 +- .../custom_operations/custom_objects.hpp | 120 +- .../custom_operations/custom_operations.hpp | 67 -- .../custom_operations_plugin.hpp | 8 +- .../wallet/include/graphene/wallet/wallet.hpp | 75 +- libraries/wallet/wallet.cpp | 125 -- tests/cli/main.cpp | 112 +- tests/common/database_fixture.cpp | 5 +- tests/custom_operations/main.cpp | 1012 ++++------------- 14 files changed, 325 insertions(+), 1481 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 483179710c..97d0b455a6 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -687,57 +687,6 @@ namespace graphene { namespace app { } // custom operations api - optional custom_operations_api::get_contact_info(std::string account_id_or_name)const - { - const auto account_id = database_api.get_account_id_from_string(account_id_or_name); - auto &index = _app.chain_database()->get_index_type().indices().get(); - auto itr = index.find(account_id); - if(itr != index.end()) - return *itr; - return optional(); - } - - vector custom_operations_api::get_account_htlc_offers(std::string account_id_or_name, - htlc_order_id_type start, uint32_t limit)const - { - FC_ASSERT(limit <= 101); - - const auto account_id = database_api.get_account_id_from_string(account_id_or_name); - vector results; - auto &index = _app.chain_database()->get_index_type().indices().get(); - - auto itr = index.lower_bound(boost::make_tuple(account_id, start)); - while(itr != index.end() && itr->bitshares_account == account_id && results.size() < limit) - { - results.push_back(*itr); - ++itr; - } - return results; - } - vector custom_operations_api::get_active_htlc_offers(htlc_order_id_type start, uint32_t limit)const - { - FC_ASSERT(limit <= 101); - - vector results; - auto db = _app.chain_database(); - auto &index = db->get_index_type().indices().get(); - auto itr = index.lower_bound(make_tuple(true, db->head_block_time(), start)); - while(itr != index.end() && itr->active && itr->expiration > db->head_block_time() && results.size() < limit) - { - results.push_back(*itr); - ++itr; - } - return results; - } - optional custom_operations_api::get_htlc_offer(htlc_order_id_type id)const - { - auto &index = _app.chain_database()->get_index_type().indices().get(); - auto itr = index.find(id); - if(itr != index.end()) - return *itr; - return optional(); - } - vector custom_operations_api::get_storage_info(std::string account_id_or_name, std::string catalog)const { diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index d0e97f76a0..b9480b0932 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -531,51 +531,11 @@ namespace graphene { namespace app { custom_operations_api(application& app):_app(app), database_api( std::ref(*app.chain_database()), &(app.get_options()) ){} - /** - * @breif Get contact information of an account - * - * @param account Account name to get info from - * - * @return The contact information of the account or empty - */ - optional get_contact_info(std::string account)const; - - /** - * @breif Get htlc offers from an account - * - * @param account Account name to get htlc offers from - * @param start ID of the most recent htlc offer to retrieve - * @param limit Maximum number of order objects to retrieve - * - * @return A vector of htlc offer objects from the account - */ - vector get_account_htlc_offers(std::string account, htlc_order_id_type start, - uint32_t limit)const; - - /** - * @breif Get all active and non expired htlc offers - * - * @param start ID of the most recent htlc offer to retrieve - * @param limit Maximum number of order objects to retrieve - * - * @return A vector of active and non expired htlc offers - */ - vector get_active_htlc_offers(htlc_order_id_type start, uint32_t limit)const; - - /** - * @breif Get htlc order offer by id - * - * @param id ID of the htlc order offer to retrieve - * - * @return A vector of active and non expired htlc offers - */ - optional get_htlc_offer(htlc_order_id_type id)const; - /** * @breif Get all stored objects of an account in a particular catalog * * @param account Account name to get info from - * @param catalog Category classification + * @param catalog Category classification. Each account can store multiple catalogs. * * @return The vector of objects of the account or empty */ @@ -722,10 +682,6 @@ FC_API(graphene::app::orders_api, (get_grouped_limit_orders) ) FC_API(graphene::app::custom_operations_api, - (get_contact_info) - (get_account_htlc_offers) - (get_active_htlc_offers) - (get_htlc_offer) (get_storage_info) ) FC_API(graphene::app::login_api, diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 875e9019c7..9cc9ee0d5e 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -35,144 +35,98 @@ custom_generic_evaluator::custom_generic_evaluator(database& db, const account_i _account = account; } -void fill_contact_object(account_contact_object& aco, account_id_type account, const account_contact_operation& op) -{ - aco.account = account; - if(op.extensions.value.name.valid()) aco.name = *op.extensions.value.name; - if(op.extensions.value.email.valid()) aco.email = *op.extensions.value.email; - if(op.extensions.value.phone.valid()) aco.phone = *op.extensions.value.phone; - if(op.extensions.value.address.valid()) aco.address = *op.extensions.value.address; - if(op.extensions.value.company.valid()) aco.company = *op.extensions.value.company; - if(op.extensions.value.url.valid()) aco.url = *op.extensions.value.url; -} - -object_id_type custom_generic_evaluator::do_apply(const account_contact_operation& op) -{ - auto &index = _db->get_index_type().indices().get(); - - auto itr = index.find(_account); - if( itr != index.end() ) - { - _db->modify( *itr, [&op, this]( account_contact_object& aco ){ - fill_contact_object(aco, _account, op); - }); - return itr->id; - } - else - { - auto created = _db->create( [&op, this]( account_contact_object& aco ) { - fill_contact_object(aco, _account, op); - }); - return created.id; - } -} - -object_id_type custom_generic_evaluator::do_apply(const create_htlc_order_operation& op) -{ - FC_ASSERT(*op.extensions.value.expiration > _db->head_block_time() + fc::seconds(3600)); - - auto order_time = _db->head_block_time(); - auto created = _db->create( [&op, &order_time, this]( htlc_order_object& hoo ) { - hoo.bitshares_account = _account; - if(op.extensions.value.bitshares_amount.valid()) hoo.bitshares_amount = *op.extensions.value.bitshares_amount; - if(op.extensions.value.blockchain.valid()) hoo.blockchain = *op.extensions.value.blockchain; - if(op.extensions.value.blockchain_account.valid()) hoo.blockchain_account = *op.extensions.value.blockchain_account; - if(op.extensions.value.blockchain_asset.valid()) hoo.blockchain_asset = *op.extensions.value.blockchain_asset; - if(op.extensions.value.blockchain_asset_precision.valid()) hoo.blockchain_asset_precision = - *op.extensions.value.blockchain_asset_precision; - if(op.extensions.value.blockchain_amount.valid()) hoo.blockchain_amount = *op.extensions.value.blockchain_amount; - if(op.extensions.value.expiration.valid()) hoo.expiration = *op.extensions.value.expiration; - if(op.extensions.value.token_contract.valid()) hoo.token_contract = *op.extensions.value.token_contract; - if(op.extensions.value.tag.valid()) hoo.tag = *op.extensions.value.tag; - - hoo.order_time = order_time; - hoo.active = true; - }); - return created.id; -} - -object_id_type custom_generic_evaluator::do_apply(const take_htlc_order_operation& op) -{ - auto &index = _db->get_index_type().indices().get(); - htlc_order_id_type htlc_order_id; - - if(op.extensions.value.htlc_order_id.valid()) { - htlc_order_id = *op.extensions.value.htlc_order_id; - auto itr = index.find(htlc_order_id); - if (itr != index.end()) { - auto close_time = _db->head_block_time(); - _db->modify(*itr, [&op, &close_time, this](htlc_order_object &hoo) { - hoo.active = false; - hoo.taker_bitshares_account = _account; - if (op.extensions.value.blockchain_account.valid()) - hoo.taker_blockchain_account = op.extensions.value.blockchain_account; - hoo.close_time = close_time; - }); - } - } - return htlc_order_id; -} - -object_id_type custom_generic_evaluator::do_apply(const account_storage_map& op) +vector custom_generic_evaluator::do_apply(const account_storage_map& op) { auto &index = _db->get_index_type().indices().get(); + vector results; if (op.extensions.value.remove.valid() && *op.extensions.value.remove) { for(auto const& row: *op.extensions.value.key_values) { auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); - if(itr != index.end()) + if(itr != index.end()) { + results.push_back(itr->id); _db->remove(*itr); + } } } else { for(auto const& row: *op.extensions.value.key_values) { + if(row.first.length() > CUSTOM_OPERATIONS_MAX_KEY_SIZE) + { + wlog("Key can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); + continue; + } auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); if(itr == index.end()) { - auto created = _db->create( [&op, this, &row]( account_storage_object& aso ) { - aso.catalog = *op.extensions.value.catalog; - aso.account = _account; - aso.key = row.first; - aso.value = row.second; - }); + try { + auto created = _db->create( [&op, this, &row]( account_storage_object& aso ) { + aso.catalog = *op.extensions.value.catalog; + aso.account = _account; + aso.key = row.first; + aso.value = fc::json::from_string(row.second); + }); + results.push_back(created.id); + } + catch(const fc::parse_error_exception& e) { wdump((e.to_detail_string())); } + catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } } else { - _db->modify(*itr, [&op, this, &row](account_storage_object &aso) { - aso.value = row.second; - }); + try { + _db->modify(*itr, [&op, this, &row](account_storage_object &aso) { + aso.value = fc::json::from_string(row.second); + }); + results.push_back(itr->id); + } + catch(const fc::parse_error_exception& e) { wdump((e.to_detail_string())); } + catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } } } } + return results; } -object_id_type custom_generic_evaluator::do_apply(const account_storage_list& op) +vector custom_generic_evaluator::do_apply(const account_storage_list& op) { - auto &index = _db->get_index_type().indices().get(); + auto &index = _db->get_index_type().indices().get(); + vector results; if (op.extensions.value.remove.valid() && *op.extensions.value.remove) { for(auto const& list_value: *op.extensions.value.values) { auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); - if(itr != index.end()) + if(itr != index.end()) { + results.push_back(itr->id); _db->remove(*itr); + } } } else { - for(auto const& list_value: *op.extensions.value.values) { + if(list_value.length() > 200) + { + wlog("List value can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); + continue; + } auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); if(itr == index.end()) { - auto created = _db->create( [&op, this, &list_value]( account_storage_object& aso ) { - aso.catalog = *op.extensions.value.catalog; - aso.account = _account; - aso.value = list_value; - }); + try { + auto created = _db->create( + [&op, this, &list_value](account_storage_object &aso) { + aso.catalog = *op.extensions.value.catalog; + aso.account = _account; + aso.subkey = list_value; + }); + results.push_back(itr->id); + } + catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } } } } + return results; } } } diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp index 80ab429dab..89ff76e59c 100644 --- a/libraries/plugins/custom_operations/custom_operations.cpp +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -25,44 +25,22 @@ namespace graphene { namespace custom_operations { -void account_contact_operation::validate()const -{ -} - -void create_htlc_order_operation::validate()const -{ - FC_ASSERT(extensions.value.bitshares_amount.valid()); - FC_ASSERT(extensions.value.bitshares_amount->amount.value > 0); - FC_ASSERT(extensions.value.blockchain.valid()); - FC_ASSERT(extensions.value.blockchain_account.valid()); - FC_ASSERT(extensions.value.blockchain_asset.valid()); - FC_ASSERT(extensions.value.blockchain_amount.valid()); - FC_ASSERT(extensions.value.expiration.valid()); -} - -void take_htlc_order_operation::validate()const -{ - FC_ASSERT(extensions.value.blockchain_account.valid()); - FC_ASSERT(extensions.value.htlc_order_id.valid()); -} - void account_storage_map::validate()const { FC_ASSERT(extensions.value.catalog.valid()); FC_ASSERT(extensions.value.key_values.valid()); FC_ASSERT(extensions.value.key_values->size() <= 10); + FC_ASSERT(extensions.value.catalog->length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE); } void account_storage_list::validate()const { FC_ASSERT(extensions.value.catalog.valid()); FC_ASSERT(extensions.value.values.valid()); FC_ASSERT(extensions.value.values->size() <= 10); + FC_ASSERT(extensions.value.catalog->length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE); } } } //graphene::custom_operations -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/custom_operations_plugin.cpp b/libraries/plugins/custom_operations/custom_operations_plugin.cpp index 9c6d3e169f..e5249c52b3 100644 --- a/libraries/plugins/custom_operations/custom_operations_plugin.cpp +++ b/libraries/plugins/custom_operations/custom_operations_plugin.cpp @@ -113,8 +113,6 @@ void custom_operations_plugin::plugin_set_program_options( void custom_operations_plugin::plugin_initialize(const boost::program_options::variables_map& options) { - database().add_index< primary_index< account_contact_index > >(); - database().add_index< primary_index< htlc_orderbook_index > >(); database().add_index< primary_index< account_storage_index > >(); database().applied_block.connect( [this]( const signed_block& b) { diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp index 32a36fdae0..50d8644105 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp @@ -34,11 +34,8 @@ class custom_generic_evaluator account_id_type _account; custom_generic_evaluator(database& db, const account_id_type account); - object_id_type do_apply(const account_contact_operation& o); - object_id_type do_apply(const create_htlc_order_operation& o); - object_id_type do_apply(const take_htlc_order_operation& o); - object_id_type do_apply(const account_storage_map& o); - object_id_type do_apply(const account_storage_list& o); + vector do_apply(const account_storage_map& o); + vector do_apply(const account_storage_list& o); }; } } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index fb24f3f9ae..bba04c807d 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -34,55 +34,11 @@ using namespace chain; #define CUSTOM_OPERATIONS_SPACE_ID 7 #endif -enum types { - account_contact = 0, - create_htlc = 1, - take_htlc = 2, - account_map = 3, - account_list = 4 -}; -enum blockchains { - eos = 0, - bitcoin = 1, - ripple = 2, - ethereum = 3 -}; - -struct account_contact_object : public abstract_object -{ - static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; - static const uint8_t type_id = account_contact; - - account_id_type account; - optional name; - optional email; - optional phone; - optional address; - optional company; - optional url; -}; +#define CUSTOM_OPERATIONS_MAX_KEY_SIZE (200) -struct htlc_order_object : public abstract_object -{ - static const uint8_t space_id = CUSTOM_OPERATIONS_SPACE_ID; - static const uint8_t type_id = create_htlc; - - account_id_type bitshares_account; - asset bitshares_amount; - blockchains blockchain; - string blockchain_account; - string blockchain_asset; - string blockchain_amount; - fc::time_point_sec expiration; - fc::time_point_sec order_time; - bool active; - - optional blockchain_asset_precision; - optional token_contract; - optional tag; - optional taker_bitshares_account; - optional taker_blockchain_account; - optional close_time; +enum types { + account_map = 0, + account_list = 1 }; struct account_storage_object : public abstract_object @@ -93,50 +49,15 @@ struct account_storage_object : public abstract_object account_id_type account; string catalog; optional key; - string value; + optional subkey; + optional value; }; struct by_custom_id; struct by_custom_account; -typedef multi_index_container< - account_contact_object, - indexed_by< - ordered_non_unique< tag, member< object, object_id_type, &object::id > >, - ordered_unique< tag, - member< account_contact_object, account_id_type, &account_contact_object::account > > - > -> account_contact_multi_index_type; - -typedef generic_index account_contact_index; - -struct by_bitshares_account; -struct by_active; -typedef multi_index_container< - htlc_order_object, - indexed_by< - ordered_non_unique< tag, member< object, object_id_type, &object::id > >, - ordered_unique< tag, - composite_key< htlc_order_object, - member< htlc_order_object, account_id_type, &htlc_order_object::bitshares_account >, - member< object, object_id_type, &object::id > - > - >, - ordered_unique< tag, - composite_key< htlc_order_object, - member< htlc_order_object, bool, &htlc_order_object::active >, - member< htlc_order_object, fc::time_point_sec, &htlc_order_object::expiration >, - member< object, object_id_type, &object::id > - > - > - > -> htlc_orderbook_multi_index_type; - -typedef generic_index htlc_orderbook_index; - struct by_account_catalog; struct by_account_catalog_key; -struct by_account_catalog_value; -struct by_account_catalog_key_value; +struct by_account_catalog_subkey; typedef multi_index_container< account_storage_object, @@ -157,19 +78,11 @@ typedef multi_index_container< member< account_storage_object, optional, &account_storage_object::key > > >, - ordered_unique< tag, - composite_key< account_storage_object, - member< account_storage_object, account_id_type, &account_storage_object::account >, - member< account_storage_object, string, &account_storage_object::catalog >, - member< account_storage_object, string, &account_storage_object::value > - > - >, - ordered_unique< tag, + ordered_non_unique< tag, composite_key< account_storage_object, member< account_storage_object, account_id_type, &account_storage_object::account >, member< account_storage_object, string, &account_storage_object::catalog >, - member< account_storage_object, optional, &account_storage_object::key >, - member< account_storage_object, string, &account_storage_object::value > + member< account_storage_object, optional, &account_storage_object::subkey > > > > @@ -177,21 +90,10 @@ typedef multi_index_container< typedef generic_index account_storage_index; -using account_contact_id_type = object_id; -using htlc_order_id_type = object_id; using account_storage_id_type = object_id; } } //graphene::custom_operations -FC_REFLECT_DERIVED( graphene::custom_operations::account_contact_object, (graphene::db::object), - (account)(name)(email)(phone)(address)(company)(url)) -FC_REFLECT_DERIVED( graphene::custom_operations::htlc_order_object, (graphene::db::object), - (bitshares_account)(bitshares_amount)(blockchain)(blockchain_account)(blockchain_asset) - (blockchain_amount)(expiration)(order_time)(active) - (blockchain_asset_precision)(token_contract)(tag)(taker_bitshares_account) - (taker_blockchain_account)(close_time)) FC_REFLECT_DERIVED( graphene::custom_operations::account_storage_object, (graphene::db::object), - (account)(catalog)(key)(value)) -FC_REFLECT_ENUM( graphene::custom_operations::types, (account_contact)(create_htlc)(take_htlc)(account_map) - (account_list)) -FC_REFLECT_ENUM( graphene::custom_operations::blockchains, (eos)(bitcoin)(ripple)(ethereum) ) + (account)(catalog)(key)(subkey)(value)) +FC_REFLECT_ENUM( graphene::custom_operations::types, (account_map)(account_list)) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp index 976302ce63..3c28dc2bbd 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp @@ -32,56 +32,6 @@ namespace graphene { namespace custom_operations { using namespace std; using graphene::protocol::account_id_type; -struct account_contact_operation : chain::base_operation -{ - struct ext - { - optional name; - optional email; - optional phone; - optional address; - optional company; - optional url; - }; - - graphene::protocol::extension extensions; - - void validate()const; -}; - -struct create_htlc_order_operation : chain::base_operation -{ - struct ext - { - optional bitshares_amount; - optional blockchain; - optional blockchain_account; - optional blockchain_asset; - optional blockchain_asset_precision; - optional blockchain_amount; - optional expiration; - optional token_contract; - optional tag; - }; - - graphene::protocol::extension extensions; - - void validate()const; -}; - -struct take_htlc_order_operation : chain::base_operation -{ - struct ext - { - optional htlc_order_id; - optional blockchain_account; - }; - - graphene::protocol::extension extensions; - - void validate()const; -}; - struct account_storage_map : chain::base_operation { struct ext @@ -113,20 +63,6 @@ struct account_storage_list : chain::base_operation } } //graphene::custom_operations -FC_REFLECT( graphene::custom_operations::account_contact_operation::ext, (name)(email)(phone)(address)(company)(url) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::account_contact_operation, (extensions) ) - -FC_REFLECT( graphene::custom_operations::create_htlc_order_operation::ext, (bitshares_amount)(blockchain) - (blockchain_account)(blockchain_asset)(blockchain_asset_precision)(blockchain_amount)(expiration) - (token_contract)(tag) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::create_htlc_order_operation, (extensions) ) - -FC_REFLECT( graphene::custom_operations::take_htlc_order_operation::ext, (htlc_order_id)(blockchain_account) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::take_htlc_order_operation, (extensions) ) - FC_REFLECT( graphene::custom_operations::account_storage_map::ext, (remove)(catalog)(key_values) ) FC_REFLECT_TYPENAME( graphene::protocol::extension ) FC_REFLECT( graphene::custom_operations::account_storage_map, (extensions) ) @@ -135,8 +71,5 @@ FC_REFLECT( graphene::custom_operations::account_storage_list::ext, (catalog)(va FC_REFLECT_TYPENAME( graphene::protocol::extension ) FC_REFLECT( graphene::custom_operations::account_storage_list, (extensions) ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_contact_operation ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::create_htlc_order_operation ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::take_htlc_order_operation ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp index d9ee4cdf61..caf3b11cb8 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -56,13 +56,7 @@ class custom_operations_plugin : public graphene::app::plugin std::unique_ptr my; }; -typedef fc::static_variant< - account_contact_operation, - create_htlc_order_operation, - take_htlc_order_operation, - account_storage_map, - account_storage_list -> custom_plugin_operation; +typedef fc::static_variant custom_plugin_operation; struct custom_operation_wrapper { uint8_t unused_data; // if first char of custom_op.data is 0xFF we unpack, this char is not used anymore then. diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 229a5df7cf..412fc4998e 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2015,76 +2015,6 @@ class wallet_api std::shared_ptr my; void encrypt_keys(); - /** - * Add account contact data by using the custom operations plugin. - * - * Each account can optionally add personal information into the blockchain - * to be retrieved by any interested party. - * - * @param account The account ID or name that we are adding additional information to. - * @param data Contact data to be added. \c account_contact_operation::ext - * @param broadcast true if you wish to broadcast the transaction - * - * @return The signed transaction - */ - signed_transaction set_contact_information(string account, account_contact_operation::ext data, bool broadcast); - - /** - * Get contact data of an account by using the custom operations plugin. - * - * If the account added contact data with @ref set_contact_information an \c account_contact_object will be - * returned. - * - * @param account Account ID or name to get contact data from. - * - * @return An \c account_contact_object or empty if account had not provided contact info yet. - */ - optional get_contact_information(string account); - - /** - * Create an HTLC offer using the custom operations plugin. - * - * The \c custom_operations_plugin maintain a list of HTLC offers to facilitate the exchange - * of tokens between bitshares and another blockchain. - * Applications and individuals can create HTLC offers by the use of this command. - * - * @param account The account in the bitshares side. - * @param data Data to create an HTLC offer. \c create_htlc_order_operation::ext - * @param broadcast true if you wish to broadcast the transaction - * - * @return The signed transaction - */ - signed_transaction create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast); - - /** - * Take an HTLC offer using the custom operation plugin. - * - * The \c custom_operations_plugin maintain a list of HTLC offers to facilitate the exchange - * of tokens between bitshares and another blockchain. - * Applications and individuals can take existing HTLC offers by the use of this command. - * Object state will change from active to inactive after the order is taken and will not be displayed by - * @ref get_active_htlc_offers call anymore. - * - * @param account The account of the taker in the bitshares side. - * @param data Data to take an already created and active HTLC offer. \c take_htlc_order_operation::ext data - * @param broadcast true if you wish to broadcast the transaction - * - * @return The signed transaction - */ - - signed_transaction take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast); - - /** - * Get active HTLC offers by using the custom operation plugin. - * - * Get the list of offers available at this time to initialize HTLC exchange with another blockchain. - * - * @param blockchain eos = 0 , bitcoin = 1, ripple = 2, ethereum = 3 - * - * @return A list of \c htlc_order_object that are active and non expired in the selected blockchain. - */ - vector get_active_htlc_offers(uint16_t blockchain); - /** * Manage account storage map(key->value) by using the custom operations plugin. * @@ -2333,7 +2263,8 @@ FC_API( graphene::wallet::wallet_api, (blind_history) (receive_blind_transfer) (get_order_book) - (set_contact_information) - (get_contact_information) + (account_store_map) + (account_store_list) + (get_account_storage) (quit) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index f534c1806a..075398a3ac 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1961,96 +1961,6 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (htlc_id)(issuer)(seconds_to_add)(broadcast) ) } - signed_transaction set_contact_information(string account, account_contact_operation::ext data, bool broadcast) - { - try - { - FC_ASSERT( !self.is_locked() ); - - account_id_type account_id = get_account(account).id; - - custom_operation op; - account_contact_operation contact; - contact.extensions.value = data; - - auto packed = fc::raw::pack(contact); - packed.insert(packed.begin(), types::account_contact); - packed.insert(packed.begin(), 0xFF); - - op.payer = account_id; - op.data = packed; - - signed_transaction tx; - tx.operations.push_back(op); - set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); - tx.validate(); - - return sign_transaction(tx, broadcast); - - } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) - } - - signed_transaction create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast) - { - try - { - FC_ASSERT( !self.is_locked() ); - FC_ASSERT(data.bitshares_amount.valid()); - fc::optional asset_obj = get_asset(data.bitshares_amount->asset_id); - FC_ASSERT(asset_obj, "Could not find asset matching ${asset}", ("asset", data.bitshares_amount->asset_id)); - - account_id_type bitshares_account_id = get_account(account).id; - - custom_operation op; - create_htlc_order_operation htlc; - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::create_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = bitshares_account_id; - op.data = packed; - - signed_transaction tx; - tx.operations.push_back(op); - set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); - tx.validate(); - - return sign_transaction(tx, broadcast); - - } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) - } - - signed_transaction take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast) - { - try - { - FC_ASSERT( !self.is_locked() ); - - account_id_type bitshares_account_id = get_account(account).id; - - custom_operation op; - take_htlc_order_operation htlc; - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::take_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = bitshares_account_id; - op.data = packed; - - signed_transaction tx; - tx.operations.push_back(op); - set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); - tx.validate(); - - return sign_transaction(tx, broadcast); - - } FC_CAPTURE_AND_RETHROW( (account)(data)(broadcast) ) - } - signed_transaction account_store_map(string account, account_storage_map::ext map, bool broadcast) { try @@ -5337,41 +5247,6 @@ order_book wallet_api::get_order_book( const string& base, const string& quote, } // custom operations -signed_transaction wallet_api::set_contact_information(string account, account_contact_operation::ext data, - bool broadcast) -{ - return my->set_contact_information(account, data, broadcast); -} - -optional wallet_api::get_contact_information(string account) -{ - return my->_custom_operations->get_contact_info(account); -} - -signed_transaction wallet_api::create_htlc_offer(string account, create_htlc_order_operation::ext data, bool broadcast) -{ - return my->create_htlc_offer(account, data, broadcast); -} - -signed_transaction wallet_api::take_htlc_offer(string account, take_htlc_order_operation::ext data, bool broadcast) -{ - return my->take_htlc_offer(account, data, broadcast); -} - -vector wallet_api::get_active_htlc_offers(uint16_t blockchain) -{ - FC_ASSERT(blockchain <= blockchains::ethereum); - - vector results; - auto orders = my->_custom_operations->get_active_htlc_offers(htlc_order_id_type(0), 100); - for(const auto order : orders) - { - if(order.blockchain == static_cast(blockchain)) - results.push_back(order); - } - return results; -} - signed_transaction wallet_api::account_store_map(string account, account_storage_map::ext map, bool broadcast) { return my->account_store_map(account, map, broadcast); diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index 9a35a34d03..f051f8606b 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1211,104 +1211,6 @@ BOOST_FIXTURE_TEST_CASE( cli_sign_message, cli_fixture ) } FC_LOG_AND_RETHROW() } -/////////////////// -// Test the contact information by custom operations plugin -/////////////////// -BOOST_FIXTURE_TEST_CASE( account_contact_information, cli_fixture ) -{ - try { - // just to fund nathan - INVOKE(upgrade_nathan_account); - - BOOST_TEST_MESSAGE("Check account information."); - auto account_contact_info = con.wallet_api_ptr->get_contact_information("nathan"); - BOOST_CHECK(!account_contact_info.valid()); // no info yet - - BOOST_TEST_MESSAGE("About to add contact information."); - - account_contact_operation::ext data; - data.name = "Nathan"; - data.email = "nathan@nathan.com"; - data.phone = "2121212121"; - data.address = "Bv DD 22"; - data.company = ""; - data.url = ""; - - signed_transaction custom_tx = con.wallet_api_ptr->set_contact_information("nathan", data, true); - - BOOST_TEST_MESSAGE("The system is generating a block."); - BOOST_CHECK(generate_block(app1)); - - BOOST_TEST_MESSAGE("Check account contact information."); - account_contact_info = con.wallet_api_ptr->get_contact_information("nathan"); - - BOOST_CHECK_EQUAL(account_contact_info->account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*account_contact_info->name, "Nathan"); - BOOST_CHECK_EQUAL(*account_contact_info->email, "nathan@nathan.com"); - BOOST_CHECK_EQUAL(*account_contact_info->phone, "2121212121"); - BOOST_CHECK_EQUAL(*account_contact_info->address, "Bv DD 22"); - BOOST_CHECK_EQUAL(*account_contact_info->company, ""); - BOOST_CHECK_EQUAL(*account_contact_info->url, ""); - - } catch( fc::exception& e ) { - edump((e.to_detail_string())); - throw; - } -} - -/////////////////// -// Test the htlc offer orderbook by custom operations plugin -/////////////////// -BOOST_FIXTURE_TEST_CASE( htlc_orderbook, cli_fixture ) -{ - try { - // create the taker account - INVOKE(create_new_account); - - auto db = app1->chain_database(); - - BOOST_TEST_MESSAGE("Adding an offer."); - - create_htlc_order_operation::ext data_maker; - data_maker.blockchain = blockchains::bitcoin; - data_maker.blockchain_account = "nathan"; - data_maker.bitshares_amount = asset(100); - data_maker.blockchain_asset = "BTC"; - data_maker.blockchain_amount = "2000"; - data_maker.expiration = db->head_block_time() + 7200; - data_maker.tag = "Some text, can be a memo"; - - signed_transaction custom_tx = con.wallet_api_ptr->create_htlc_offer("nathan", data_maker, true); - - BOOST_TEST_MESSAGE("The system is generating a block."); - BOOST_CHECK(generate_block(app1)); - - BOOST_TEST_MESSAGE("Get active htlc offers."); - auto offers = con.wallet_api_ptr->get_active_htlc_offers(blockchains::bitcoin); - if(offers[0].blockchain == blockchains::bitcoin) { - BOOST_CHECK_EQUAL(offers[0].id.instance(), 0); - } - - BOOST_TEST_MESSAGE("Taking the offfer."); - take_htlc_order_operation::ext data_taker; - data_taker.htlc_order_id = offers[0].id; - data_taker.blockchain_account = "nathan"; - - custom_tx = con.wallet_api_ptr->take_htlc_offer("jmjatlanta", data_taker, true); - - BOOST_TEST_MESSAGE("The system is generating a block."); - BOOST_CHECK(generate_block(app1)); - - BOOST_TEST_MESSAGE("Get active htlc offers."); - offers = con.wallet_api_ptr->get_active_htlc_offers(blockchains::bitcoin); - BOOST_CHECK_EQUAL(offers.size(), 0); - - } catch( fc::exception& e ) { - edump((e.to_detail_string())); - throw; - } -} - /////////////////// // Test the general storage by custom operations plugin /////////////////// @@ -1323,8 +1225,8 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_TEST_MESSAGE("Storing in a map."); flat_map pairs; - pairs["key1"] = "value1"; - pairs["key2"] = "value2"; + pairs["key1"] = fc::json::to_string("value1"); + pairs["key2"] = fc::json::to_string("value2"); account_storage_map::ext map; @@ -1343,12 +1245,12 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_CHECK_EQUAL(nathan_map[0].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_map[0].catalog, "any"); BOOST_CHECK_EQUAL(*nathan_map[0].key, "key1"); - BOOST_CHECK_EQUAL(nathan_map[0].value, "value1"); + BOOST_CHECK_EQUAL(nathan_map[0].value->as_string(), "value1"); BOOST_CHECK_EQUAL(nathan_map[1].id.instance(), 1); BOOST_CHECK_EQUAL(nathan_map[1].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_map[1].catalog, "any"); BOOST_CHECK_EQUAL(*nathan_map[1].key, "key2"); - BOOST_CHECK_EQUAL(nathan_map[1].value, "value2"); + BOOST_CHECK_EQUAL(nathan_map[1].value->as_string(), "value2"); BOOST_TEST_MESSAGE("Storing in a list."); @@ -1373,15 +1275,15 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_CHECK_EQUAL(nathan_list[0].id.instance(), 2); BOOST_CHECK_EQUAL(nathan_list[0].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[0].catalog, "favourites"); - BOOST_CHECK_EQUAL(nathan_list[0].value, "banana"); + BOOST_CHECK_EQUAL(*nathan_list[0].subkey, "banana"); BOOST_CHECK_EQUAL(nathan_list[1].id.instance(), 3); BOOST_CHECK_EQUAL(nathan_list[1].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[1].catalog, "favourites"); - BOOST_CHECK_EQUAL(nathan_list[1].value, "chocolate"); + BOOST_CHECK_EQUAL(*nathan_list[1].subkey, "chocolate"); BOOST_CHECK_EQUAL(nathan_list[2].id.instance(), 4); BOOST_CHECK_EQUAL(nathan_list[2].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[2].catalog, "favourites"); - BOOST_CHECK_EQUAL(nathan_list[2].value, "milk"); + BOOST_CHECK_EQUAL(*nathan_list[2].subkey, "milk"); } catch( fc::exception& e ) { edump((e.to_detail_string())); diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index a1e1f60961..87fce373b3 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -332,9 +332,8 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) ahiplugin->plugin_startup(); } - if(current_test_name == "custom_operations_account_contact_test" || - current_test_name == "custom_operations_htlc_bitshares_eos_test" || - current_test_name == "custom_operations_account_storage_test") { + if(current_test_name == "custom_operations_account_storage_map_test" || + current_test_name == "custom_operations_account_storage_list_test") { auto custom_operations_plugin = app.register_plugin(); custom_operations_plugin->plugin_set_app(&app); custom_operations_plugin->plugin_initialize(options); diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index b671dcf291..22ec469f82 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -40,432 +40,235 @@ using namespace graphene::custom_operations; BOOST_FIXTURE_TEST_SUITE( custom_operation_tests, database_fixture ) -BOOST_AUTO_TEST_CASE(custom_operations_account_contact_test) +void map_operation(flat_map& pairs, bool remove, string& catalog, account_id_type& account, + private_key& pk, database& db) +{ + signed_transaction trx; + set_expiration(db, trx); + + custom_operation op; + account_storage_map store; + account_storage_map::ext data; + + store.extensions.value.key_values = pairs; + store.extensions.value.remove = remove; + store.extensions.value.catalog = catalog; + + auto packed = fc::raw::pack(store); + packed.insert(packed.begin(), types::account_map); + packed.insert(packed.begin(), 0xFF); + + op.payer = account; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + trx.sign(pk, db.get_chain_id()); + PUSH_TX(db, trx, ~0); + trx.clear(); +} + +void list_operation(flat_set& list, bool remove, string& catalog, account_id_type& account, + private_key& pk, database& db) +{ + signed_transaction trx; + set_expiration(db, trx); + + custom_operation op; + account_storage_list storage_list; + account_storage_list::ext data; + + storage_list.extensions.value.values = list; + storage_list.extensions.value.remove = remove; + storage_list.extensions.value.catalog = "contact_list"; + + auto packed = fc::raw::pack(storage_list); + packed.insert(packed.begin(), types::account_list); + packed.insert(packed.begin(), 0xFF); + + op.payer = account; + op.data = packed; + op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); + trx.operations.push_back(op); + trx.sign(pk, db.get_chain_id()); + PUSH_TX(db, trx, ~0); + trx.clear(); +} + +BOOST_AUTO_TEST_CASE(custom_operations_account_storage_map_test) { try { - ACTORS((nathan)(alice)); + ACTORS((nathan)(alice)(robert)(patty)); app.enable_plugin("custom_operations"); custom_operations_api custom_operations_api(app); generate_block(); - fc::usleep(fc::milliseconds(200)); - enable_fees(); - signed_transaction trx; - set_expiration(db, trx); int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); transfer(committee_account, nathan_id, asset(init_balance)); transfer(committee_account, alice_id, asset(init_balance)); - // nathan adds account data via custom operation - { - custom_operation op; - account_contact_operation contact; - account_contact_operation::ext data; - - data.name = "Nathan"; - data.email = "nathan@nathan.com"; - data.phone = "+1 434343434343"; - data.address = ""; - data.company = "Bitshares"; - data.url = "http://nathan.com/"; - - contact.extensions.value = data; - - auto packed = fc::raw::pack(contact); - packed.insert(packed.begin(), types::account_contact); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - // alice adds account data via custom operation - { - custom_operation op; - account_contact_operation contact; - - account_contact_operation::ext data; - data.name = "Alice"; - data.email = "alice@alice.com"; - data.phone = ""; - data.address = "Some Street 456, Somewhere"; - data.company = ""; - data.url = "http://alice.com/"; - - contact.extensions.value = data; - - auto packed = fc::raw::pack(contact); - packed.insert(packed.begin(), types::account_contact); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + // catalog is indexed so cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) + std::string catalog(201, 'a'); + flat_map pairs; + pairs["key"] = fc::json::to_string("value"); + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - // check nathan account data with the api - account_contact_object contact_results_nathan = *custom_operations_api.get_contact_info("nathan"); - BOOST_CHECK_EQUAL(contact_results_nathan.account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*contact_results_nathan.name, "Nathan"); - BOOST_CHECK_EQUAL(*contact_results_nathan.email, "nathan@nathan.com"); - BOOST_CHECK_EQUAL(*contact_results_nathan.phone, "+1 434343434343"); - BOOST_CHECK_EQUAL(*contact_results_nathan.address, ""); - BOOST_CHECK_EQUAL(*contact_results_nathan.company, "Bitshares"); - BOOST_CHECK_EQUAL(*contact_results_nathan.url, "http://nathan.com/"); - - // check alice account data with the api - account_contact_object contact_results_alice = *custom_operations_api.get_contact_info("alice"); - BOOST_CHECK_EQUAL(contact_results_alice.account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*contact_results_alice.name, "Alice"); - BOOST_CHECK_EQUAL(*contact_results_alice.email, "alice@alice.com"); - BOOST_CHECK_EQUAL(*contact_results_alice.phone, ""); - BOOST_CHECK_EQUAL(*contact_results_alice.address, "Some Street 456, Somewhere"); - BOOST_CHECK_EQUAL(*contact_results_alice.company, ""); - BOOST_CHECK_EQUAL(*contact_results_alice.url, "http://alice.com/"); - - // alice update her data - { - custom_operation op; - account_contact_operation contact; - - account_contact_operation::ext data; - data.name = "Alice Smith"; - data.email = "alicesmith@alice.com"; - data.phone = "+1 1111 11 1111"; - data.address = "Some Street 456, Somewhere"; - data.company = ""; - data.url = "http://alice.com/"; - - contact.extensions.value = data; - - auto packed = fc::raw::pack(contact); - packed.insert(packed.begin(), types::account_contact); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } + auto storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); + + // keys are indexed so they cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) + catalog = "whatever"; + std::string key(201, 'a'); + pairs.clear(); + pairs[key] = fc::json::to_string("value"); + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - // check alice account updates with the api - contact_results_alice = *custom_operations_api.get_contact_info("alice"); - BOOST_CHECK_EQUAL(contact_results_alice.account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*contact_results_alice.name, "Alice Smith"); - BOOST_CHECK_EQUAL(*contact_results_alice.email, "alicesmith@alice.com"); - BOOST_CHECK_EQUAL(*contact_results_alice.phone, "+1 1111 11 1111"); - BOOST_CHECK_EQUAL(*contact_results_alice.address, "Some Street 456, Somewhere"); - BOOST_CHECK_EQUAL(*contact_results_alice.company, ""); - BOOST_CHECK_EQUAL(*contact_results_alice.url, "http://alice.com/"); - - // alice try to update nathan data - { - custom_operation op; - account_contact_operation contact; - - account_contact_operation::ext data; - data.name = "Not my account"; - data.phone = "Fake phone"; - data.email = "Fake email"; - data.address = "Fake address"; - data.company = "Fake company"; - data.url = "http://fake.com"; - - contact.extensions.value = data; - - auto packed = fc::raw::pack(contact); - packed.insert(packed.begin(), types::account_contact); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } + + storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); + + // nathan adds key-value data via custom operation to a settings catalog + catalog = "settings"; + pairs.clear(); + pairs["language"] = fc::json::to_string("en"); + pairs["image_url"] = fc::json::to_string("http://some.image.url/img.jpg"); + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - // operation will pass but data will be unchanged, exception was produced in plug in - contact_results_nathan = *custom_operations_api.get_contact_info("nathan"); - BOOST_CHECK(contact_results_nathan.account.instance.value == 16 ); - BOOST_CHECK(*contact_results_nathan.name != "Not my account"); - BOOST_CHECK(*contact_results_nathan.phone != "Fake phone"); - BOOST_CHECK(*contact_results_nathan.email != "Fake email"); -} -catch (fc::exception &e) { - edump((e.to_detail_string())); - throw; -} } -BOOST_AUTO_TEST_CASE(custom_operations_htlc_bitshares_eos_test) -{ try { + // check nathan stored data with the api + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://some.image.url/img.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); - ACTORS((nathan)(alice)(bob)(carol)); + // edit some stuff and add new stuff + pairs.clear(); + pairs["image_url"] = fc::json::to_string("http://new.image.url/newimg.jpg"); + pairs["theme"] = fc::json::to_string("dark"); + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); + generate_block(); - app.enable_plugin("custom_operations"); - custom_operations_api custom_operations_api(app); + // check old and new stuff + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 3 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); + BOOST_CHECK_EQUAL(*storage_results_nathan[2].key, "theme"); + BOOST_CHECK_EQUAL(storage_results_nathan[2].value->as_string(), "dark"); + // delete stuff from the storage + pairs.clear(); + pairs["theme"] = fc::json::to_string("dark"); + map_operation(pairs, true, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - enable_fees(); - signed_transaction trx; - set_expiration(db, trx); + // theme is removed from the storage + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); - int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); + // delete stuff that it is not there + pairs.clear(); + pairs["nothere"] = fc::json::to_string("nothere"); + map_operation(pairs, true, catalog, nathan_id, nathan_private_key, db); + generate_block(); - transfer(committee_account, nathan_id, asset(init_balance)); - transfer(committee_account, alice_id, asset(init_balance)); - transfer(committee_account, bob_id, asset(init_balance)); - transfer(committee_account, carol_id, asset(init_balance)); + // nothing changes + storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); + BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); - enable_fees(); + // add more than 10 storage items in 1 operation is not allowed + pairs.clear(); + pairs["key1"] = fc::json::to_string("value1"); + pairs["key2"] = fc::json::to_string("value2"); + pairs["key3"] = fc::json::to_string("value3"); + pairs["key4"] = fc::json::to_string("value4"); + pairs["key5"] = fc::json::to_string("value5"); + pairs["key6"] = fc::json::to_string("value6"); + pairs["key7"] = fc::json::to_string("value7"); + pairs["key8"] = fc::json::to_string("value8"); + pairs["key9"] = fc::json::to_string("value9"); + pairs["key10"] = fc::json::to_string("value10"); + pairs["key11"] = fc::json::to_string("value11"); + + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); + generate_block(); - // alice creates an order - { - custom_operation op; - create_htlc_order_operation htlc; - - create_htlc_order_operation::ext data; - data.blockchain = blockchains::eos; - data.blockchain_account = "alice"; - data.bitshares_amount = asset(10); - data.blockchain_asset = "EOS"; - data.blockchain_amount = "10"; - data.expiration = db.head_block_time() + fc::seconds(7200); - - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::create_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - // bob creates an order - { - custom_operation op; - create_htlc_order_operation htlc; - - create_htlc_order_operation::ext data; - data.blockchain = blockchains::eos; - data.blockchain_account = "bob"; - data.bitshares_amount = asset(100); - data.blockchain_asset = "EOS"; - data.blockchain_amount = "100"; - data.expiration = db.head_block_time() + fc::seconds(7200); - data.tag = "Some text, can be a memo"; - - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::create_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = bob_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, bob_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - // carol creates an order with missing information (blockchain_amount), will fail in the validator - { - custom_operation op; - create_htlc_order_operation htlc; - - create_htlc_order_operation::ext data; - data.blockchain = blockchains::eos; - data.blockchain_account = "carol"; - data.bitshares_amount = asset(10); - data.blockchain_asset = "EOS"; - data.expiration = db.head_block_time() + fc::seconds(7200); - - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::create_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = carol_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, carol_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } + // alice, duplicated keys in storage, only second value will be added + pairs.clear(); + catalog = "random"; + pairs["key1"] = fc::json::to_string("value1"); + pairs["key1"] = fc::json::to_string("value2"); + map_operation(pairs, false, catalog, alice_id, alice_private_key, db); + generate_block(); + vector storage_results_alice = custom_operations_api.get_storage_info("alice", "random"); + BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); + BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); + BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "key1"); + BOOST_CHECK_EQUAL(storage_results_alice[0].value->as_string(), "value2"); + + // add an object + pairs.clear(); + catalog = "account_object"; + pairs["nathan"] = fc::json::to_string(nathan); + map_operation(pairs, false, catalog, alice_id, alice_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - // test the get_account_htlc_offers api call for alice - vector htlc_offers_results_alice = custom_operations_api.get_account_htlc_offers("alice", - htlc_order_id_type(0), 100); - BOOST_CHECK_EQUAL(htlc_offers_results_alice.size(), 1); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].id.instance(), 0); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_account.instance.value, 17); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_account, "alice" ); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].bitshares_amount.amount.value, 10); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offers_results_alice[0].blockchain_amount, "10"); - BOOST_CHECK(htlc_offers_results_alice[0].active); - - // test the get_htlc_offer api call with alice order - auto htlc_offer = custom_operations_api.get_htlc_offer(htlc_order_id_type(0)); - BOOST_CHECK_EQUAL(htlc_offer->id.instance(), 0); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_account.instance.value, 17); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_account, "alice" ); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.amount.value, 10); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_amount, "10"); - BOOST_CHECK(htlc_offer->active); - - // test the get_account_htlc_offers api call for bob - vector htlc_offers_results_bob = custom_operations_api.get_account_htlc_offers("bob", - htlc_order_id_type(0), 100); - - BOOST_CHECK_EQUAL(htlc_offers_results_bob.size(), 1); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].id.instance(), 1); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_account.instance.value, 18); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_account, "bob" ); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].bitshares_amount.amount.value, 100); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offers_results_bob[0].blockchain_amount, "100"); - BOOST_CHECK(htlc_offers_results_bob[0].active); - if(htlc_offers_results_bob[0].tag.valid()) - BOOST_CHECK_EQUAL(*htlc_offers_results_bob[0].tag, "Some text, can be a memo"); - - // get all active offers - vector htlc_offers_results_active = custom_operations_api.get_active_htlc_offers( - htlc_order_id_type(0), 100); - - BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 2); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].id.instance(), 0); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_account.instance.value, 17); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_account, "alice" ); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.amount.value, 10); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_amount, "10"); - BOOST_CHECK(htlc_offers_results_active[0].active); - - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].id.instance(), 1); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_account.instance.value, 18); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_account, "bob" ); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].bitshares_amount.amount.value, 100); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offers_results_active[1].blockchain_amount, "100"); - BOOST_CHECK(htlc_offers_results_active[1].active); - if(htlc_offers_results_active[0].tag.valid()) - BOOST_CHECK_EQUAL(*htlc_offers_results_active[0].tag, "Some text, can be a memo"); - - // nathan takes alice order - { - custom_operation op; - take_htlc_order_operation htlc; - - take_htlc_order_operation::ext data; - data.htlc_order_id = htlc_offers_results_alice[0].id; - data.blockchain_account = "nathan"; - - htlc.extensions.value = data; - - auto packed = fc::raw::pack(htlc); - packed.insert(packed.begin(), types::take_htlc); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } + + storage_results_alice = custom_operations_api.get_storage_info("alice", "account_object"); + BOOST_CHECK_EQUAL(storage_results_alice.size(), 1); + BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17); + BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "nathan"); + BOOST_CHECK_EQUAL(storage_results_alice[0].value->as(20).name, "nathan"); + + // add 2 more objects + pairs.clear(); + catalog = "account_object"; + pairs["robert"] = fc::json::to_string(robert); + pairs["patty"] = fc::json::to_string(patty); + map_operation(pairs, false, catalog, alice_id, alice_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - // check the taken object - htlc_offer = custom_operations_api.get_htlc_offer(htlc_order_id_type(0)); - BOOST_CHECK_EQUAL(htlc_offer->id.instance(), 0); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_account.instance.value, 17); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_account, "alice" ); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offer->bitshares_amount.amount.value, 10); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offer->blockchain_amount, "10"); - BOOST_CHECK(!htlc_offer->active); - BOOST_CHECK_EQUAL(htlc_offer->taker_bitshares_account->instance.value, 16); - BOOST_CHECK_EQUAL(*htlc_offer->taker_blockchain_account, "nathan"); - - // alice order was taken, bob order still up for get_active_htlc_offers - htlc_offers_results_active = custom_operations_api.get_active_htlc_offers(htlc_order_id_type(0), 100); - BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 1); - - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].id.instance(), 1); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_account.instance.value, 18); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_account, "bob"); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.asset_id.instance.value, 0); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].bitshares_amount.amount.value, 100); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_asset, "EOS"); - BOOST_CHECK_EQUAL(htlc_offers_results_active[0].blockchain_amount, "100"); - BOOST_CHECK(htlc_offers_results_active[0].active); - if(htlc_offers_results_active[0].tag.valid()) - BOOST_CHECK_EQUAL(*htlc_offers_results_active[0].tag, "Some text, can be a memo"); - - // make bob order expire - generate_blocks(7201); - fc::usleep(fc::milliseconds(200)); - - htlc_offers_results_active = custom_operations_api.get_active_htlc_offers(htlc_order_id_type(0), 100); - BOOST_CHECK_EQUAL(htlc_offers_results_active.size(), 0); -} + storage_results_alice = custom_operations_api.get_storage_info("alice", "account_object"); + BOOST_CHECK_EQUAL(storage_results_alice.size(), 3); + BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17); + BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "nathan"); + BOOST_CHECK_EQUAL(storage_results_alice[0].value->as(20).name, "nathan"); + BOOST_CHECK_EQUAL(storage_results_alice[1].account.instance.value, 17); + BOOST_CHECK_EQUAL(*storage_results_alice[1].key, "patty"); + BOOST_CHECK_EQUAL(storage_results_alice[1].value->as(20).name, "patty"); + BOOST_CHECK_EQUAL(*storage_results_alice[2].key, "robert"); + BOOST_CHECK_EQUAL(storage_results_alice[2].value->as(20).name, "robert"); +} catch (fc::exception &e) { edump((e.to_detail_string())); throw; } } -BOOST_AUTO_TEST_CASE(custom_operations_account_storage_test) +BOOST_AUTO_TEST_CASE(custom_operations_account_storage_list_test) { try { ACTORS((nathan)(alice)(robert)(patty)); @@ -474,434 +277,107 @@ try { custom_operations_api custom_operations_api(app); generate_block(); - fc::usleep(fc::milliseconds(200)); - enable_fees(); - signed_transaction trx; - set_expiration(db, trx); int64_t init_balance(10000 * GRAPHENE_BLOCKCHAIN_PRECISION); transfer(committee_account, nathan_id, asset(init_balance)); transfer(committee_account, alice_id, asset(init_balance)); - // nathan adds key-value data via custom operation to a settings catalog - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["language"] = "en"; - pairs["image_url"] = "http://some.image.url/img.jpg"; - - store.extensions.value.key_values = pairs; - store.extensions.value.catalog = "settings"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } + // catalog is indexed so cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) + std::string catalog(201, 'a'); + flat_set accounts; + accounts.insert(robert.name); + list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + generate_block(); + + auto storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); + // keys are indexed so they cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) + catalog = "whatever"; + std::string value(201, 'a'); + accounts.clear(); + accounts.insert(value); + list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - // check nathan stored data with the api - vector storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); - BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://some.image.url/img.jpg"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); + storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); // nathan add a list of accounts to storage - { - custom_operation op; - account_storage_list list; - account_storage_list::ext data; - - flat_set accounts; - accounts.insert(alice.name); - accounts.insert(robert.name); - - list.extensions.value.values = accounts; - list.extensions.value.catalog = "contact_list"; - - auto packed = fc::raw::pack(list); - packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + accounts.clear(); + accounts.insert(alice.name); + accounts.insert(robert.name); + catalog = "contact_list"; + list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); // get the account list for nathan, check alice and robert are there storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, alice.name); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].subkey, robert.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, robert.name); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].subkey, alice.name); // add a value into account list already there - { - custom_operation op; - account_storage_list list; - account_storage_list::ext data; - - flat_set accounts; - accounts.insert(alice.name); - - list.extensions.value.values = accounts; - list.extensions.value.catalog = "contact_list"; - - auto packed = fc::raw::pack(list); - packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + accounts.clear(); + accounts.insert(alice.name); + list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); // nothing changes storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, alice.name); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].subkey, robert.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, robert.name); + BOOST_CHECK_EQUAL(*storage_results_nathan[1].subkey, alice.name); // delete alice from the list - { - custom_operation op; - account_storage_list list; - account_storage_list::ext data; - - flat_set accounts; - accounts.insert(alice.name); - - list.extensions.value.values = accounts; - list.extensions.value.remove = true; - list.extensions.value.catalog = "contact_list"; - - auto packed = fc::raw::pack(list); - packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + accounts.clear(); + accounts.insert(alice.name); + list_operation(accounts, true, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); // alice gone storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 1 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, robert.name); - - // add and edit more stuff to the storage - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["image_url"] = "http://new.image.url/newimg.jpg"; - pairs["theme"] = "dark"; - - store.extensions.value.key_values = pairs; - store.extensions.value.catalog = "settings"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - generate_block(); - fc::usleep(fc::milliseconds(200)); - - // check old and new stuff - storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); - BOOST_CHECK_EQUAL(storage_results_nathan.size(), 3 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); - BOOST_CHECK_EQUAL(*storage_results_nathan[2].key, "theme"); - BOOST_CHECK_EQUAL(storage_results_nathan[2].value, "dark"); - - // delete stuff from the storage - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["theme"] = "dark"; - - store.extensions.value.key_values = pairs; - store.extensions.value.remove = true; - store.extensions.value.catalog = "settings"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - generate_block(); - fc::usleep(fc::milliseconds(200)); - - // theme is removed from the storage - storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); - BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); - - // delete stuff that it is not there - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["nothere"] = "nothere"; - - store.extensions.value.key_values = pairs; - store.extensions.value.remove = true; - store.extensions.value.catalog = "settings"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - generate_block(); - fc::usleep(fc::milliseconds(200)); - - // nothing changes - storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); - BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); - BOOST_CHECK_EQUAL(storage_results_nathan[0].value, "http://new.image.url/newimg.jpg"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); - BOOST_CHECK_EQUAL(storage_results_nathan[1].value, "en"); - - // add more than 10 storage items in 1 operation is not allowed - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["key1"] = "value1"; - pairs["key2"] = "value2"; - pairs["key3"] = "value3"; - pairs["key4"] = "value4"; - pairs["key5"] = "value5"; - pairs["key6"] = "value6"; - pairs["key7"] = "value7"; - pairs["key8"] = "value8"; - pairs["key9"] = "value9"; - pairs["key10"] = "value10"; - pairs["key11"] = "value11"; - - store.extensions.value.key_values = pairs; - store.extensions.value.catalog = "settings"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - generate_block(); - fc::usleep(fc::milliseconds(200)); + BOOST_CHECK_EQUAL(*storage_results_nathan[0].subkey, robert.name); // add more than 10 accounts to the list in 1 operation is not allowed - { - custom_operation op; - account_storage_list list; - account_storage_list::ext data; - - flat_set accounts; - accounts.insert("init0"); - accounts.insert("init1"); - accounts.insert("init2"); - accounts.insert("init3"); - accounts.insert("init4"); - accounts.insert("init5"); - accounts.insert("init6"); - accounts.insert("init7"); - accounts.insert("init8"); - accounts.insert("init9"); - accounts.insert("init10"); - - list.extensions.value.values = accounts; - list.extensions.value.catalog = "contact_list"; - list.extensions.value.remove = true; - - auto packed = fc::raw::pack(list); - packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); - - op.payer = nathan_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, nathan_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - - generate_block(); - fc::usleep(fc::milliseconds(200)); - - // alice, duplicated keys in storage, only second value will be added - { - custom_operation op; - account_storage_map store; - account_storage_map::ext data; - - flat_map pairs; - pairs["key1"] = "value1"; - pairs["key1"] = "value2"; - - store.extensions.value.key_values = pairs; - store.extensions.value.catalog = "random"; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + accounts.clear(); + accounts.insert("init0"); + accounts.insert("init1"); + accounts.insert("init2"); + accounts.insert("init3"); + accounts.insert("init4"); + accounts.insert("init5"); + accounts.insert("init6"); + accounts.insert("init7"); + accounts.insert("init8"); + accounts.insert("init9"); + accounts.insert("init10"); + list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - - vector storage_results_alice = custom_operations_api.get_storage_info("alice", "random"); - BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); - BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "key1"); - BOOST_CHECK_EQUAL(storage_results_alice[0].value, "value2"); // duplicated accounts in the list, only 1 will be inserted - { - custom_operation op; - account_storage_list list; - account_storage_list::ext data; - - flat_set accounts; - accounts.insert(robert.name); - accounts.insert(robert.name); - - list.extensions.value.values = accounts; - list.extensions.value.catalog = "contact_list"; - - auto packed = fc::raw::pack(list); - packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); - - op.payer = alice_id; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx, ~0); - trx.clear(); - } - + accounts.clear(); + accounts.insert(robert.name); + accounts.insert(robert.name); + list_operation(accounts, false, catalog, alice_id, alice_private_key, db); generate_block(); - fc::usleep(fc::milliseconds(200)); - storage_results_alice = custom_operations_api.get_storage_info("alice", "contact_list"); + auto storage_results_alice = custom_operations_api.get_storage_info("alice", "contact_list"); BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); - BOOST_CHECK_EQUAL(storage_results_alice[0].value, robert.name); - + BOOST_CHECK_EQUAL(*storage_results_alice[0].subkey, robert.name); } catch (fc::exception &e) { edump((e.to_detail_string())); throw; } } - BOOST_AUTO_TEST_SUITE_END() From 0f8560be0186f0323bc456683fdc3ec3d06e86b3 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 11 Sep 2019 12:44:36 -0300 Subject: [PATCH 058/534] change logs to dlog, remove not needed catch --- .../custom_operations/custom_evaluators.cpp | 26 +++++++------------ .../custom_operations_plugin.cpp | 2 +- tests/custom_operations/main.cpp | 10 +++++++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 9cc9ee0d5e..372ecb630c 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -54,7 +54,7 @@ vector custom_generic_evaluator::do_apply(const account_storage_ for(auto const& row: *op.extensions.value.key_values) { if(row.first.length() > CUSTOM_OPERATIONS_MAX_KEY_SIZE) { - wlog("Key can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); + dlog("Key can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); continue; } auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); @@ -69,8 +69,7 @@ vector custom_generic_evaluator::do_apply(const account_storage_ }); results.push_back(created.id); } - catch(const fc::parse_error_exception& e) { wdump((e.to_detail_string())); } - catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } + catch(const fc::parse_error_exception& e) { dlog(e.to_detail_string()); } } else { @@ -80,8 +79,7 @@ vector custom_generic_evaluator::do_apply(const account_storage_ }); results.push_back(itr->id); } - catch(const fc::parse_error_exception& e) { wdump((e.to_detail_string())); } - catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } + catch(const fc::parse_error_exception& e) { dlog((e.to_detail_string())); } } } } @@ -107,22 +105,18 @@ vector custom_generic_evaluator::do_apply(const account_storage_ for(auto const& list_value: *op.extensions.value.values) { if(list_value.length() > 200) { - wlog("List value can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); + dlog("List value can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); continue; } auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); if(itr == index.end()) { - try { - auto created = _db->create( - [&op, this, &list_value](account_storage_object &aso) { - aso.catalog = *op.extensions.value.catalog; - aso.account = _account; - aso.subkey = list_value; - }); - results.push_back(itr->id); - } - catch(const fc::assert_exception& e) { wdump((e.to_detail_string())); } + auto created = _db->create([&op, this, &list_value](account_storage_object &aso) { + aso.catalog = *op.extensions.value.catalog; + aso.account = _account; + aso.subkey = list_value; + }); + results.push_back(itr->id); } } } diff --git a/libraries/plugins/custom_operations/custom_operations_plugin.cpp b/libraries/plugins/custom_operations/custom_operations_plugin.cpp index e5249c52b3..caf2f750ba 100644 --- a/libraries/plugins/custom_operations/custom_operations_plugin.cpp +++ b/libraries/plugins/custom_operations/custom_operations_plugin.cpp @@ -73,7 +73,7 @@ void custom_operations_plugin_impl::onBlock( const signed_block& b ) unpacked.op.visit(vtor); } catch (fc::exception e) { // only api node will know if the unpack, validate or apply fails - wlog("Error: ${ex} in operation: ${op}", ("ex", e.to_detail_string())("op", fc::json::to_string(custom_op))); + dlog("Error: ${ex} in operation: ${op}", ("ex", e.to_detail_string())("op", fc::json::to_string(custom_op))); continue; } } diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 22ec469f82..783de79489 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -131,6 +131,16 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); + // creating a map with bad json as value is not allowed + catalog = "whatever"; + pairs.clear(); + pairs["key"] = "value"; + map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); + generate_block(); + + storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); + BOOST_CHECK_EQUAL(storage_results_nathan.size(), 0 ); + // nathan adds key-value data via custom operation to a settings catalog catalog = "settings"; pairs.clear(); From 1740fbe4e794471c5a0bf10fab3ea229d59257ec Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Wed, 11 Sep 2019 15:40:44 +0200 Subject: [PATCH 059/534] Fix #831 - check witness signature before adding block to fork db --- libraries/chain/db_block.cpp | 45 +++++++++++++++++-- .../chain/include/graphene/chain/database.hpp | 2 + .../include/graphene/chain/fork_database.hpp | 7 ++- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index dbcf94b3fa..91c7ff7ec8 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -130,10 +131,17 @@ bool database::push_block(const signed_block& new_block, uint32_t skip) bool database::_push_block(const signed_block& new_block) { try { uint32_t skip = get_node_properties().skip_flags; - // TODO: If the block is greater than the head block and before the next maintenance interval - // verify that the block signer is in the current set of active witnesses. - shared_ptr new_head = _fork_db.push_block(new_block); + if( _fork_db.head() && new_block.block_num() > 1 ) + { + // verify that the block signer is in the current set of active witnesses. + shared_ptr prev_block = _fork_db.fetch_block( new_block.previous ); + GRAPHENE_ASSERT( prev_block, unlinkable_block_exception, "block does not link to known chain" ); + if( prev_block->scheduled_witnesses && !(skip&(skip_witness_schedule_check|skip_witness_signature)) ) + verify_signing_witness( new_block, *prev_block ); + } + + const shared_ptr new_head = _fork_db.push_block(new_block); //If the head block from the longest chain does not build off of the current head, we need to switch forks. if( new_head->data.previous != head_block_id() ) { @@ -159,6 +167,7 @@ bool database::_push_block(const signed_block& new_block) try { undo_database::session session = _undo_db.start_undo_session(); apply_block( (*ritr)->data, skip ); + update_witnesses( **ritr ); _block_id_to_block.store( (*ritr)->id, (*ritr)->data ); session.commit(); } @@ -203,6 +212,7 @@ bool database::_push_block(const signed_block& new_block) try { auto session = _undo_db.start_undo_session(); apply_block(new_block, skip); + update_witnesses( *new_head ); _block_id_to_block.store(new_block.id(), new_block); session.commit(); } catch ( const fc::exception& e ) { @@ -214,6 +224,35 @@ bool database::_push_block(const signed_block& new_block) return false; } FC_CAPTURE_AND_RETHROW( (new_block) ) } +void database::verify_signing_witness( const signed_block& new_block, const fork_item& fork_entry )const +{ + FC_ASSERT( new_block.timestamp > fork_entry.data.timestamp ); + uint32_t slot_num = ( new_block.timestamp - fork_entry.next_block_time ).to_seconds() / block_interval(); + uint64_t index = ( fork_entry.next_block_aslot + slot_num ) % fork_entry.scheduled_witnesses->size(); + const auto& scheduled_witness = (*fork_entry.scheduled_witnesses)[index]; + FC_ASSERT( new_block.witness == scheduled_witness.first, "Witness produced block at wrong time", + ("block witness",new_block.witness)("scheduled",scheduled_witness)("slot_num",slot_num) ); + FC_ASSERT( new_block.validate_signee( scheduled_witness.second ) ); +} + +void database::update_witnesses( fork_item& fork_entry )const +{ + if( fork_entry.scheduled_witnesses ) return; + + const dynamic_global_property_object& dpo = get_dynamic_global_properties(); + fork_entry.next_block_aslot = dpo.current_aslot + 1; + fork_entry.next_block_time = get_slot_time( 1 ); + + const witness_schedule_object& wso = get_witness_schedule_object(); + fork_entry.scheduled_witnesses = std::make_shared< vector< pair< witness_id_type, public_key_type > > >(); + fork_entry.scheduled_witnesses->reserve( wso.current_shuffled_witnesses.size() ); + for( size_t i = 0; i < wso.current_shuffled_witnesses.size(); ++i ) + { + const auto& witness = wso.current_shuffled_witnesses[i](*this); + fork_entry.scheduled_witnesses->emplace_back( wso.current_shuffled_witnesses[i], witness.signing_key ); + } +} + /** * Attempts to push the transaction into the pending queue * diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 395818389b..5afb83ab1e 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -499,6 +499,8 @@ namespace graphene { namespace chain { const witness_object& validate_block_header( uint32_t skip, const signed_block& next_block )const; const witness_object& _validate_block_header( const signed_block& next_block )const; + void verify_signing_witness( const signed_block& new_block, const fork_item& fork_entry )const; + void update_witnesses( fork_item& fork_entry )const; void create_block_summary(const signed_block& next_block); //////////////////// db_witness_schedule.cpp //////////////////// diff --git a/libraries/chain/include/graphene/chain/fork_database.hpp b/libraries/chain/include/graphene/chain/fork_database.hpp index f5214a8859..a4bc251735 100644 --- a/libraries/chain/include/graphene/chain/fork_database.hpp +++ b/libraries/chain/include/graphene/chain/fork_database.hpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #pragma once + #include #include @@ -32,7 +33,6 @@ #include #include - namespace graphene { namespace chain { using boost::multi_index_container; using namespace boost::multi_index; @@ -48,6 +48,11 @@ namespace graphene { namespace chain { uint32_t num; // initialized in ctor block_id_type id; signed_block data; + + // contains witness block signing keys scheduled *after* the block has been applied + shared_ptr< vector< pair< witness_id_type, public_key_type > > > scheduled_witnesses; + uint64_t next_block_aslot; + fc::time_point_sec next_block_time; }; typedef shared_ptr item_ptr; From d87c70ea8cc2a6571262a94193f542619e790acd Mon Sep 17 00:00:00 2001 From: John Jones Date: Wed, 11 Sep 2019 12:13:44 -0500 Subject: [PATCH 060/534] remove needless option addition --- programs/delayed_node/main.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index b760113049..42e2c333ef 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -70,12 +70,6 @@ int main(int argc, char** argv) { "Space-separated list of plugins to activate"); ; - bpo::variables_map options; - - bpo::options_description cli, cfg; - node.set_program_options(cli, cfg); - cfg_options.add(cfg); - cfg_options.add_options() ("plugins", bpo::value()->default_value("delayed_node account_history market_history"), "Space-separated list of plugins to activate"); @@ -85,6 +79,7 @@ int main(int argc, char** argv) { auto market_history_plug = node.register_plugin(); // add plugin options to config + bpo::variables_map options; try { bpo::options_description cli, cfg; From 26cdff2c73701f7a4d543f31f7693dc4cc274f51 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Thu, 15 Aug 2019 14:40:34 +0200 Subject: [PATCH 061/534] Remove unused account_referrer_index --- libraries/chain/account_object.cpp | 13 ------------- libraries/chain/db_init.cpp | 1 - .../include/graphene/chain/account_object.hpp | 16 ---------------- 3 files changed, 30 deletions(-) diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index d72d29536a..1840916113 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -256,19 +256,6 @@ void account_member_index::object_modified(const object& after) } -void account_referrer_index::object_inserted( const object& obj ) -{ -} -void account_referrer_index::object_removed( const object& obj ) -{ -} -void account_referrer_index::about_to_modify( const object& before ) -{ -} -void account_referrer_index::object_modified( const object& after ) -{ -} - const uint8_t balances_by_account_index::bits = 20; const uint64_t balances_by_account_index::mask = (1ULL << balances_by_account_index::bits) - 1; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 124cede1eb..41f7f7018f 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -191,7 +191,6 @@ void database::initialize_indexes() auto acnt_index = add_index< primary_index >(); // ~1 million accounts per chunk acnt_index->add_secondary_index(); - acnt_index->add_secondary_index(); add_index< primary_index >(); // 256 members per chunk add_index< primary_index >(); // 1024 witnesses per chunk diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 70aa0f78e9..1f610eb55a 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -324,22 +324,6 @@ namespace graphene { namespace chain { }; - /** - * @brief This secondary index will allow a reverse lookup of all accounts that have been referred by - * a particular account. - */ - class account_referrer_index : public secondary_index - { - public: - virtual void object_inserted( const object& obj ) override; - virtual void object_removed( const object& obj ) override; - virtual void about_to_modify( const object& before ) override; - virtual void object_modified( const object& after ) override; - - /** maps the referrer to the set of accounts that they have referred */ - map< account_id_type, set > referred_by; - }; - /** * @brief This secondary index will allow fast access to the balance objects * that belonging to an account. From ff11b33193aac157a8837fd9d1e7d7555eaa875f Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 11 Sep 2019 15:37:29 -0300 Subject: [PATCH 062/534] remove subkey --- .../plugins/custom_operations/custom_evaluators.cpp | 4 ++-- .../graphene/custom_operations/custom_objects.hpp | 11 +---------- tests/cli/main.cpp | 6 +++--- tests/custom_operations/main.cpp | 12 ++++++------ 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 372ecb630c..6a97619e19 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -87,7 +87,7 @@ vector custom_generic_evaluator::do_apply(const account_storage_ } vector custom_generic_evaluator::do_apply(const account_storage_list& op) { - auto &index = _db->get_index_type().indices().get(); + auto &index = _db->get_index_type().indices().get(); vector results; if (op.extensions.value.remove.valid() && *op.extensions.value.remove) @@ -114,7 +114,7 @@ vector custom_generic_evaluator::do_apply(const account_storage_ auto created = _db->create([&op, this, &list_value](account_storage_object &aso) { aso.catalog = *op.extensions.value.catalog; aso.account = _account; - aso.subkey = list_value; + aso.key = list_value; }); results.push_back(itr->id); } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index bba04c807d..4488538af0 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -49,7 +49,6 @@ struct account_storage_object : public abstract_object account_id_type account; string catalog; optional key; - optional subkey; optional value; }; @@ -57,7 +56,6 @@ struct by_custom_id; struct by_custom_account; struct by_account_catalog; struct by_account_catalog_key; -struct by_account_catalog_subkey; typedef multi_index_container< account_storage_object, @@ -77,13 +75,6 @@ typedef multi_index_container< member< account_storage_object, string, &account_storage_object::catalog >, member< account_storage_object, optional, &account_storage_object::key > > - >, - ordered_non_unique< tag, - composite_key< account_storage_object, - member< account_storage_object, account_id_type, &account_storage_object::account >, - member< account_storage_object, string, &account_storage_object::catalog >, - member< account_storage_object, optional, &account_storage_object::subkey > - > > > > account_storage_multi_index_type; @@ -95,5 +86,5 @@ using account_storage_id_type = object_id Date: Thu, 15 Aug 2019 15:21:19 +0200 Subject: [PATCH 063/534] Move account_member_index to api_helper_indexs plugin --- libraries/chain/db_init.cpp | 4 +--- .../api_helper_indexes/api_helper_indexes.cpp | 4 ++++ tests/cli/main.cpp | 2 ++ tests/common/database_fixture.cpp | 12 +++++++----- tests/common/database_fixture.hpp | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 41f7f7018f..12bd2cd583 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -189,9 +189,7 @@ void database::initialize_indexes() add_index< primary_index >(); // 8192 assets per chunk add_index< primary_index >(); - auto acnt_index = add_index< primary_index >(); // ~1 million accounts per chunk - acnt_index->add_secondary_index(); - + add_index< primary_index >(); // ~1 million accounts per chunk add_index< primary_index >(); // 256 members per chunk add_index< primary_index >(); // 1024 witnesses per chunk add_index< primary_index >(); diff --git a/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp b/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp index e99e29b9c1..0470c6aab6 100644 --- a/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp +++ b/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp @@ -149,6 +149,10 @@ void api_helper_indexes::plugin_startup() amount_in_collateral = database().add_secondary_index< primary_index, amount_in_collateral_index >(); for( const auto& call : database().get_index_type().indices() ) amount_in_collateral->object_inserted( call ); + + auto& account_members = *database().add_secondary_index< primary_index, account_member_index >(); + for( const auto& account : database().get_index_type< account_index >().indices() ) + account_members.object_inserted( account ); } } } diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index 43dfaabfb3..24bab00b98 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -125,6 +126,7 @@ std::shared_ptr start_application(fc::temp_directory app1->register_plugin(true); app1->register_plugin< graphene::market_history::market_history_plugin >(true); app1->register_plugin< graphene::grouped_orders::grouped_orders_plugin>(true); + app1->register_plugin< graphene::api_helper_indexes::api_helper_indexes>(true); app1->startup_plugins(); boost::program_options::variables_map cfg; #ifdef _WIN32 diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index c8bf3517d9..db76bc65ab 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -125,8 +125,10 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) /** * Test specific settings */ - auto current_test_name = boost::unit_test::framework::current_test_case().p_name.value; - auto current_test_suite_id = boost::unit_test::framework::current_test_case().p_parent_id; + const auto current_test_name = boost::unit_test::framework::current_test_case().p_name.value; + const auto current_test_suite_id = boost::unit_test::framework::current_test_case().p_parent_id; + const auto current_suite_name = boost::unit_test::framework::get(current_test_suite_id) + .p_name.value; if (current_test_name == "get_account_history_operations") { options.insert(std::make_pair("max-ops-per-account", boost::program_options::variable_value((uint64_t)75, false))); @@ -292,7 +294,7 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) esplugin->plugin_initialize(options); esplugin->plugin_startup(); } - else if( boost::unit_test::framework::get(current_test_suite_id).p_name.value != "performance_tests" ) + else if( current_suite_name != "performance_tests" ) { auto ahplugin = app.register_plugin(); ahplugin->plugin_set_app(&app); @@ -323,7 +325,7 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) esobjects_plugin->plugin_initialize(options); esobjects_plugin->plugin_startup(); } - else if( current_test_name == "asset_in_collateral" ) + else if( current_test_name == "asset_in_collateral" || current_suite_name == "database_api_tests" ) { auto ahiplugin = app.register_plugin(); ahiplugin->plugin_set_app(&app); @@ -431,7 +433,7 @@ string database_fixture::generate_anon_acct_name() // to workaround issue #46 return "anon-acct-x" + std::to_string( anon_acct_count++ ); } -bool database_fixture::validation_current_test_name_for_setting_api_limit(string & current_test_name) const +bool database_fixture::validation_current_test_name_for_setting_api_limit( const string& current_test_name ) const { vector valid_testcase {"api_limit_get_account_history_operations","api_limit_get_account_history" ,"api_limit_get_grouped_limit_orders","api_limit_get_relative_account_history" diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index e626475fb0..a3cc5624df 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -371,7 +371,7 @@ struct database_fixture { vector< operation_history_object > get_operation_history( account_id_type account_id )const; vector< graphene::market_history::order_history_object > get_market_order_history( asset_id_type a, asset_id_type b )const; - bool validation_current_test_name_for_setting_api_limit (string & current_test_name) const; + bool validation_current_test_name_for_setting_api_limit( const string& current_test_name )const; /**** * @brief return htlc fee parameters From a3160582db7bb5d6260cdace863dee34d9257c5c Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Thu, 15 Aug 2019 16:43:45 +0200 Subject: [PATCH 064/534] Move required_approval_index to api_helper_indexes plugin --- libraries/chain/db_init.cpp | 5 +---- .../plugins/api_helper_indexes/api_helper_indexes.cpp | 5 +++++ tests/common/database_fixture.cpp | 4 +++- tests/tests/database_tests.cpp | 8 ++++---- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 12bd2cd583..bc7167d8bb 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -194,10 +194,7 @@ void database::initialize_indexes() add_index< primary_index >(); // 1024 witnesses per chunk add_index< primary_index >(); add_index< primary_index >(); - - auto prop_index = add_index< primary_index >(); - prop_index->add_secondary_index(); - + add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); diff --git a/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp b/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp index 0470c6aab6..25644b3f65 100644 --- a/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp +++ b/libraries/plugins/api_helper_indexes/api_helper_indexes.cpp @@ -24,6 +24,7 @@ #include #include +#include namespace graphene { namespace api_helper_indexes { @@ -153,6 +154,10 @@ void api_helper_indexes::plugin_startup() auto& account_members = *database().add_secondary_index< primary_index, account_member_index >(); for( const auto& account : database().get_index_type< account_index >().indices() ) account_members.object_inserted( account ); + + auto& approvals = *database().add_secondary_index< primary_index, required_approval_index >(); + for( const auto& proposal : database().get_index_type< proposal_index >().indices() ) + approvals.object_inserted( proposal ); } } } diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index db76bc65ab..f7c85c18c8 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -325,7 +325,9 @@ database_fixture::database_fixture(const fc::time_point_sec &initial_timestamp) esobjects_plugin->plugin_initialize(options); esobjects_plugin->plugin_startup(); } - else if( current_test_name == "asset_in_collateral" || current_suite_name == "database_api_tests" ) + else if( current_test_name == "asset_in_collateral" + || current_test_name == "htlc_database_api" + || current_suite_name == "database_api_tests" ) { auto ahiplugin = app.register_plugin(); ahiplugin->plugin_set_app(&app); diff --git a/tests/tests/database_tests.cpp b/tests/tests/database_tests.cpp index 3978bd3da7..742bf39795 100644 --- a/tests/tests/database_tests.cpp +++ b/tests/tests/database_tests.cpp @@ -229,8 +229,8 @@ BOOST_AUTO_TEST_CASE( required_approval_index_test ) // see https://github.com/b database db1; db1.initialize_indexes(); - const auto& proposals = db1.get_index_type< primary_index< proposal_index > >(); - const auto& required_approvals = proposals.get_secondary_index< required_approval_index >()._account_to_proposals; + const auto& required_approvals = db1.add_secondary_index, required_approval_index>() + ->_account_to_proposals; // Create a proposal const auto& prop = db1.create( [this,alice_id,agnetha_id]( object& o ) { @@ -279,8 +279,8 @@ BOOST_AUTO_TEST_CASE( required_approval_index_test ) // see https://github.com/b database db2; db2.initialize_indexes(); const auto& reloaded_proposals = db2.get_index_type< primary_index< proposal_index > >(); - const auto& reloaded_approvals = reloaded_proposals.get_secondary_index() - ._account_to_proposals; + const auto& reloaded_approvals = db2.add_secondary_index, required_approval_index>() + ->_account_to_proposals; const_cast< primary_index< proposal_index >& >( reloaded_proposals ).load( serialized ); const auto& prop2 = *reloaded_proposals.indices().begin(); From 8d263e189ab342ed38f127a6b382ef80edc58484 Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Thu, 15 Aug 2019 16:56:59 +0200 Subject: [PATCH 065/534] Add grouped order index after replay --- libraries/plugins/grouped_orders/grouped_orders_plugin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp b/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp index ef1ae04cae..7ffc3a1ced 100644 --- a/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp +++ b/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp @@ -279,12 +279,13 @@ void grouped_orders_plugin::plugin_initialize(const boost::program_options::vari else my->_tracked_groups = fc::json::from_string("[10,100]").as>(2); - database().add_secondary_index< primary_index, detail::limit_order_group_index >( my->_tracked_groups ); - } FC_CAPTURE_AND_RETHROW() } void grouped_orders_plugin::plugin_startup() { + auto& groups = *database().add_secondary_index< primary_index, detail::limit_order_group_index >( my->_tracked_groups ); + for( const auto& order : database().get_index_type< limit_order_index >().indices() ) + groups.object_inserted( order ); } const flat_set& grouped_orders_plugin::tracked_groups() const From 6a12446b958d3a7ff26edbe1372a9cb74f65550b Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Wed, 11 Sep 2019 20:07:01 -0300 Subject: [PATCH 066/534] remove complexity from operations by replacing extension by normal fields --- .../custom_operations/custom_evaluators.cpp | 24 ++++----- .../custom_operations/custom_operations.cpp | 12 ++--- .../custom_operations/custom_objects.hpp | 4 +- .../custom_operations/custom_operations.hpp | 32 +++-------- .../wallet/include/graphene/wallet/wallet.hpp | 14 +++-- libraries/wallet/wallet.cpp | 28 ++++++---- tests/cli/main.cpp | 24 +++------ tests/custom_operations/main.cpp | 54 +++++++++---------- 8 files changed, 87 insertions(+), 105 deletions(-) diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 6a97619e19..50eec94c96 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -40,10 +40,10 @@ vector custom_generic_evaluator::do_apply(const account_storage_ auto &index = _db->get_index_type().indices().get(); vector results; - if (op.extensions.value.remove.valid() && *op.extensions.value.remove) + if (op.remove) { - for(auto const& row: *op.extensions.value.key_values) { - auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); + for(auto const& row: op.key_values) { + auto itr = index.find(make_tuple(_account, op.catalog, row.first)); if(itr != index.end()) { results.push_back(itr->id); _db->remove(*itr); @@ -51,18 +51,18 @@ vector custom_generic_evaluator::do_apply(const account_storage_ } } else { - for(auto const& row: *op.extensions.value.key_values) { + for(auto const& row: op.key_values) { if(row.first.length() > CUSTOM_OPERATIONS_MAX_KEY_SIZE) { dlog("Key can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); continue; } - auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, row.first)); + auto itr = index.find(make_tuple(_account, op.catalog, row.first)); if(itr == index.end()) { try { auto created = _db->create( [&op, this, &row]( account_storage_object& aso ) { - aso.catalog = *op.extensions.value.catalog; + aso.catalog = op.catalog; aso.account = _account; aso.key = row.first; aso.value = fc::json::from_string(row.second); @@ -90,11 +90,11 @@ vector custom_generic_evaluator::do_apply(const account_storage_ auto &index = _db->get_index_type().indices().get(); vector results; - if (op.extensions.value.remove.valid() && *op.extensions.value.remove) + if (op.remove) { - for(auto const& list_value: *op.extensions.value.values) { + for(auto const& list_value: op.values) { - auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); + auto itr = index.find(make_tuple(_account, op.catalog, list_value)); if(itr != index.end()) { results.push_back(itr->id); _db->remove(*itr); @@ -102,17 +102,17 @@ vector custom_generic_evaluator::do_apply(const account_storage_ } } else { - for(auto const& list_value: *op.extensions.value.values) { + for(auto const& list_value: op.values) { if(list_value.length() > 200) { dlog("List value can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); continue; } - auto itr = index.find(make_tuple(_account, *op.extensions.value.catalog, list_value)); + auto itr = index.find(make_tuple(_account, op.catalog, list_value)); if(itr == index.end()) { auto created = _db->create([&op, this, &list_value](account_storage_object &aso) { - aso.catalog = *op.extensions.value.catalog; + aso.catalog = op.catalog; aso.account = _account; aso.key = list_value; }); diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp index 89ff76e59c..2e5bfd1c4d 100644 --- a/libraries/plugins/custom_operations/custom_operations.cpp +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -27,17 +27,13 @@ namespace graphene { namespace custom_operations { void account_storage_map::validate()const { - FC_ASSERT(extensions.value.catalog.valid()); - FC_ASSERT(extensions.value.key_values.valid()); - FC_ASSERT(extensions.value.key_values->size() <= 10); - FC_ASSERT(extensions.value.catalog->length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE); + FC_ASSERT(key_values.size() <= 10); + FC_ASSERT(catalog.length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE && catalog.length() > 0); } void account_storage_list::validate()const { - FC_ASSERT(extensions.value.catalog.valid()); - FC_ASSERT(extensions.value.values.valid()); - FC_ASSERT(extensions.value.values->size() <= 10); - FC_ASSERT(extensions.value.catalog->length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE); + FC_ASSERT(values.size() <= 10); + FC_ASSERT(catalog.length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE && catalog.length() > 0); } } } //graphene::custom_operations diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index 4488538af0..9b910f99d1 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -48,7 +48,7 @@ struct account_storage_object : public abstract_object account_id_type account; string catalog; - optional key; + string key; optional value; }; @@ -73,7 +73,7 @@ typedef multi_index_container< composite_key< account_storage_object, member< account_storage_object, account_id_type, &account_storage_object::account >, member< account_storage_object, string, &account_storage_object::catalog >, - member< account_storage_object, optional, &account_storage_object::key > + member< account_storage_object, string, &account_storage_object::key > > > > diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp index 3c28dc2bbd..0c5a61de9e 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations.hpp @@ -34,42 +34,26 @@ using graphene::protocol::account_id_type; struct account_storage_map : chain::base_operation { - struct ext - { - optional remove; - optional catalog; - optional> key_values; - }; - - graphene::protocol::extension extensions; + bool remove; + string catalog; + flat_map key_values; void validate()const; }; struct account_storage_list : chain::base_operation { - struct ext - { - optional remove; - optional catalog; - optional> values; - }; - - graphene::protocol::extension extensions; + bool remove; + string catalog; + flat_set values; void validate()const; }; - } } //graphene::custom_operations -FC_REFLECT( graphene::custom_operations::account_storage_map::ext, (remove)(catalog)(key_values) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::account_storage_map, (extensions) ) - -FC_REFLECT( graphene::custom_operations::account_storage_list::ext, (catalog)(values)(remove) ) -FC_REFLECT_TYPENAME( graphene::protocol::extension ) -FC_REFLECT( graphene::custom_operations::account_storage_list, (extensions) ) +FC_REFLECT( graphene::custom_operations::account_storage_map, (remove)(catalog)(key_values) ) +FC_REFLECT( graphene::custom_operations::account_storage_list, (remove)(catalog)(values) ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 412fc4998e..6942733432 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2022,12 +2022,15 @@ class wallet_api * to be retrieved by any interested party. * * @param account The account ID or name that we are adding additional information to. - * @param data Storage data to be added. \c account_storage_map::ext + * @param catalog The name of the catalog the operation will insert data to. + * @param remove true if you want to remove stuff from a catalog. + * @param key_values The map to be inserted/removed to/from the catalog * @param broadcast true if you wish to broadcast the transaction * * @return The signed transaction */ - signed_transaction account_store_map(string account, account_storage_map::ext map, bool broadcast); + signed_transaction account_store_map(string account, string catalog, bool remove, + flat_map key_values, bool broadcast); /** * Manage a accounts list(values)by using the custom operations plugin. @@ -2036,12 +2039,15 @@ class wallet_api * to be retrieved by any interested party. Can be used as a whitelist, address book, etc. * * @param account The account ID or name that we are adding additional information to. - * @param data List data to be added. \c account_storage_list::ext + * @param catalog The name of the catalog the operation will insert data to. + * @param remove true if you want to remove stuff from a catalog. + * @param values The list of strings to be inserted/removed to/from the catalog. * @param broadcast true if you wish to broadcast the transaction * * @return The signed transaction */ - signed_transaction account_store_list(string account, account_storage_list::ext data, bool broadcast); + signed_transaction account_store_list(string account, string catalog, bool remove, flat_set values, + bool broadcast); /** * Get \c account_storage_object of an account by using the custom operations plugin. diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 075398a3ac..f1f2c67709 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1961,7 +1961,8 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (htlc_id)(issuer)(seconds_to_add)(broadcast) ) } - signed_transaction account_store_map(string account, account_storage_map::ext map, bool broadcast) + signed_transaction account_store_map(string account, string catalog, bool remove, flat_map key_values, + bool broadcast) { try { @@ -1971,7 +1972,9 @@ class wallet_api_impl custom_operation op; account_storage_map store; - store.extensions.value = map; + store.catalog = catalog; + store.remove = remove; + store.key_values = key_values; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_map); @@ -1987,10 +1990,11 @@ class wallet_api_impl return sign_transaction(tx, broadcast); - } FC_CAPTURE_AND_RETHROW( (account)(map)(broadcast) ) + } FC_CAPTURE_AND_RETHROW( (account)(remove)(catalog)(key_values)(broadcast) ) } - signed_transaction account_store_list(string account, account_storage_list::ext list, bool broadcast) + signed_transaction account_store_list(string account, string catalog, bool remove, flat_set values, + bool broadcast) { try { @@ -2000,7 +2004,9 @@ class wallet_api_impl custom_operation op; account_storage_list store; - store.extensions.value = list; + store.remove = remove; + store.catalog = catalog; + store.values = values; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_list); @@ -2016,7 +2022,7 @@ class wallet_api_impl return sign_transaction(tx, broadcast); - } FC_CAPTURE_AND_RETHROW( (account)(list)(broadcast) ) + } FC_CAPTURE_AND_RETHROW( (account)(remove)(catalog)(values)(broadcast) ) } vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) @@ -5247,14 +5253,16 @@ order_book wallet_api::get_order_book( const string& base, const string& quote, } // custom operations -signed_transaction wallet_api::account_store_map(string account, account_storage_map::ext map, bool broadcast) +signed_transaction wallet_api::account_store_map(string account, string catalog, bool remove, + flat_map key_values, bool broadcast) { - return my->account_store_map(account, map, broadcast); + return my->account_store_map(account, catalog, remove, key_values, broadcast); } -signed_transaction wallet_api::account_store_list(string account, account_storage_list::ext list, bool broadcast) +signed_transaction wallet_api::account_store_list(string account, string catalog, bool remove, flat_set values, + bool broadcast) { - return my->account_store_list(account, list, broadcast); + return my->account_store_list(account, catalog, remove, values, broadcast); } vector wallet_api::get_account_storage(string account, string catalog) diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index f13b8f64c1..8f8c82cd91 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1228,12 +1228,7 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) pairs["key1"] = fc::json::to_string("value1"); pairs["key2"] = fc::json::to_string("value2"); - account_storage_map::ext map; - - map.key_values = pairs; - map.catalog = "any"; - - con.wallet_api_ptr->account_store_map("nathan", map, true); + con.wallet_api_ptr->account_store_map("nathan", "any", false, pairs, true); BOOST_TEST_MESSAGE("The system is generating a block."); BOOST_CHECK(generate_block(app1)); @@ -1244,12 +1239,12 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_CHECK_EQUAL(nathan_map[0].id.instance(), 0); BOOST_CHECK_EQUAL(nathan_map[0].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_map[0].catalog, "any"); - BOOST_CHECK_EQUAL(*nathan_map[0].key, "key1"); + BOOST_CHECK_EQUAL(nathan_map[0].key, "key1"); BOOST_CHECK_EQUAL(nathan_map[0].value->as_string(), "value1"); BOOST_CHECK_EQUAL(nathan_map[1].id.instance(), 1); BOOST_CHECK_EQUAL(nathan_map[1].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_map[1].catalog, "any"); - BOOST_CHECK_EQUAL(*nathan_map[1].key, "key2"); + BOOST_CHECK_EQUAL(nathan_map[1].key, "key2"); BOOST_CHECK_EQUAL(nathan_map[1].value->as_string(), "value2"); BOOST_TEST_MESSAGE("Storing in a list."); @@ -1259,12 +1254,7 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) favs.insert("milk"); favs.insert("banana"); - account_storage_list::ext list; - - list.values = favs; - list.catalog = "favourites"; - - con.wallet_api_ptr->account_store_list("nathan", list, true); + con.wallet_api_ptr->account_store_list("nathan", "favourites", false, favs, true); BOOST_TEST_MESSAGE("The system is generating a block."); BOOST_CHECK(generate_block(app1)); @@ -1275,15 +1265,15 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_CHECK_EQUAL(nathan_list[0].id.instance(), 2); BOOST_CHECK_EQUAL(nathan_list[0].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[0].catalog, "favourites"); - BOOST_CHECK_EQUAL(*nathan_list[0].key, "banana"); + BOOST_CHECK_EQUAL(nathan_list[0].key, "banana"); BOOST_CHECK_EQUAL(nathan_list[1].id.instance(), 3); BOOST_CHECK_EQUAL(nathan_list[1].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[1].catalog, "favourites"); - BOOST_CHECK_EQUAL(*nathan_list[1].key, "chocolate"); + BOOST_CHECK_EQUAL(nathan_list[1].key, "chocolate"); BOOST_CHECK_EQUAL(nathan_list[2].id.instance(), 4); BOOST_CHECK_EQUAL(nathan_list[2].account.instance.value, 17); BOOST_CHECK_EQUAL(nathan_list[2].catalog, "favourites"); - BOOST_CHECK_EQUAL(*nathan_list[2].key, "milk"); + BOOST_CHECK_EQUAL(nathan_list[2].key, "milk"); } catch( fc::exception& e ) { edump((e.to_detail_string())); diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 5539c69d56..8eeabbefbd 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -48,11 +48,10 @@ void map_operation(flat_map& pairs, bool remove, string& catalog custom_operation op; account_storage_map store; - account_storage_map::ext data; - store.extensions.value.key_values = pairs; - store.extensions.value.remove = remove; - store.extensions.value.catalog = catalog; + store.key_values = pairs; + store.remove = remove; + store.catalog = catalog; auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_map); @@ -75,11 +74,10 @@ void list_operation(flat_set& list, bool remove, string& catalog, accoun custom_operation op; account_storage_list storage_list; - account_storage_list::ext data; - storage_list.extensions.value.values = list; - storage_list.extensions.value.remove = remove; - storage_list.extensions.value.catalog = "contact_list"; + storage_list.values = list; + storage_list.remove = remove; + storage_list.catalog = "contact_list"; auto packed = fc::raw::pack(storage_list); packed.insert(packed.begin(), types::account_list); @@ -153,10 +151,10 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, "image_url"); BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://some.image.url/img.jpg"); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, "language"); BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); // edit some stuff and add new stuff @@ -170,12 +168,12 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 3 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, "image_url"); BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, "language"); BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); - BOOST_CHECK_EQUAL(*storage_results_nathan[2].key, "theme"); + BOOST_CHECK_EQUAL(storage_results_nathan[2].key, "theme"); BOOST_CHECK_EQUAL(storage_results_nathan[2].value->as_string(), "dark"); // delete stuff from the storage @@ -188,10 +186,10 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, "image_url"); BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, "language"); BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); // delete stuff that it is not there @@ -204,10 +202,10 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "settings"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, "image_url"); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, "image_url"); BOOST_CHECK_EQUAL(storage_results_nathan[0].value->as_string(), "http://new.image.url/newimg.jpg"); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, "language"); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, "language"); BOOST_CHECK_EQUAL(storage_results_nathan[1].value->as_string(), "en"); // add more than 10 storage items in 1 operation is not allowed @@ -238,7 +236,7 @@ try { vector storage_results_alice = custom_operations_api.get_storage_info("alice", "random"); BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "key1"); + BOOST_CHECK_EQUAL(storage_results_alice[0].key, "key1"); BOOST_CHECK_EQUAL(storage_results_alice[0].value->as_string(), "value2"); // add an object @@ -251,7 +249,7 @@ try { storage_results_alice = custom_operations_api.get_storage_info("alice", "account_object"); BOOST_CHECK_EQUAL(storage_results_alice.size(), 1); BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17); - BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "nathan"); + BOOST_CHECK_EQUAL(storage_results_alice[0].key, "nathan"); BOOST_CHECK_EQUAL(storage_results_alice[0].value->as(20).name, "nathan"); // add 2 more objects @@ -265,12 +263,12 @@ try { storage_results_alice = custom_operations_api.get_storage_info("alice", "account_object"); BOOST_CHECK_EQUAL(storage_results_alice.size(), 3); BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17); - BOOST_CHECK_EQUAL(*storage_results_alice[0].key, "nathan"); + BOOST_CHECK_EQUAL(storage_results_alice[0].key, "nathan"); BOOST_CHECK_EQUAL(storage_results_alice[0].value->as(20).name, "nathan"); BOOST_CHECK_EQUAL(storage_results_alice[1].account.instance.value, 17); - BOOST_CHECK_EQUAL(*storage_results_alice[1].key, "patty"); + BOOST_CHECK_EQUAL(storage_results_alice[1].key, "patty"); BOOST_CHECK_EQUAL(storage_results_alice[1].value->as(20).name, "patty"); - BOOST_CHECK_EQUAL(*storage_results_alice[2].key, "robert"); + BOOST_CHECK_EQUAL(storage_results_alice[2].key, "robert"); BOOST_CHECK_EQUAL(storage_results_alice[2].value->as(20).name, "robert"); } catch (fc::exception &e) { @@ -327,9 +325,9 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, robert.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, alice.name); // add a value into account list already there accounts.clear(); @@ -341,9 +339,9 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, robert.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[1].key, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, alice.name); // delete alice from the list accounts.clear(); @@ -355,7 +353,7 @@ try { storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 1 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(*storage_results_nathan[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, robert.name); // add more than 10 accounts to the list in 1 operation is not allowed accounts.clear(); @@ -383,7 +381,7 @@ try { auto storage_results_alice = custom_operations_api.get_storage_info("alice", "contact_list"); BOOST_CHECK_EQUAL(storage_results_alice.size(), 1 ); BOOST_CHECK_EQUAL(storage_results_alice[0].account.instance.value, 17 ); - BOOST_CHECK_EQUAL(*storage_results_alice[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_alice[0].key, robert.name); } catch (fc::exception &e) { edump((e.to_detail_string())); From 4637af12a75ed683fba202d0c8a810c99c5b6537 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 12 Sep 2019 10:56:17 -0300 Subject: [PATCH 067/534] remove the 0xFF byte --- .../plugins/custom_operations/custom_operations_plugin.cpp | 6 +++--- .../graphene/custom_operations/custom_operations_plugin.hpp | 6 ------ libraries/wallet/wallet.cpp | 2 -- tests/custom_operations/main.cpp | 2 -- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/libraries/plugins/custom_operations/custom_operations_plugin.cpp b/libraries/plugins/custom_operations/custom_operations_plugin.cpp index caf2f750ba..cfdf145d9b 100644 --- a/libraries/plugins/custom_operations/custom_operations_plugin.cpp +++ b/libraries/plugins/custom_operations/custom_operations_plugin.cpp @@ -64,13 +64,13 @@ void custom_operations_plugin_impl::onBlock( const signed_block& b ) const custom_operation& custom_op = o_operation->op.get(); - if(custom_op.data.size() == 0 || uint8_t(custom_op.data.data()[0]) != 0xFF) + if(custom_op.data.size() == 0) continue; try { - auto unpacked = fc::raw::unpack(custom_op.data); + auto unpacked = fc::raw::unpack(custom_op.data); custom_op_visitor vtor(db, custom_op.fee_payer()); - unpacked.op.visit(vtor); + unpacked.visit(vtor); } catch (fc::exception e) { // only api node will know if the unpack, validate or apply fails dlog("Error: ${ex} in operation: ${op}", ("ex", e.to_detail_string())("op", fc::json::to_string(custom_op))); diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp index caf3b11cb8..cd75e565d6 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -58,11 +58,6 @@ class custom_operations_plugin : public graphene::app::plugin typedef fc::static_variant custom_plugin_operation; -struct custom_operation_wrapper { - uint8_t unused_data; // if first char of custom_op.data is 0xFF we unpack, this char is not used anymore then. - custom_plugin_operation op; -}; - struct custom_op_visitor { typedef void result_type; @@ -82,4 +77,3 @@ struct custom_op_visitor } } //graphene::custom_operations FC_REFLECT_TYPENAME( graphene::custom_operations::custom_plugin_operation ) -FC_REFLECT( graphene::custom_operations::custom_operation_wrapper, (unused_data)(op) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index f1f2c67709..7c4ddfe232 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1978,7 +1978,6 @@ class wallet_api_impl auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); op.payer = account_id; op.data = packed; @@ -2010,7 +2009,6 @@ class wallet_api_impl auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); op.payer = account_id; op.data = packed; diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 8eeabbefbd..574263a087 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -55,7 +55,6 @@ void map_operation(flat_map& pairs, bool remove, string& catalog auto packed = fc::raw::pack(store); packed.insert(packed.begin(), types::account_map); - packed.insert(packed.begin(), 0xFF); op.payer = account; op.data = packed; @@ -81,7 +80,6 @@ void list_operation(flat_set& list, bool remove, string& catalog, accoun auto packed = fc::raw::pack(storage_list); packed.insert(packed.begin(), types::account_list); - packed.insert(packed.begin(), 0xFF); op.payer = account; op.data = packed; From 085f4d6e1e477c48e6022bd7aa32e533f0d10411 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 12 Sep 2019 12:37:14 -0300 Subject: [PATCH 068/534] remove list operation --- .../custom_operations/custom_evaluators.cpp | 44 +-------- .../custom_operations/custom_operations.cpp | 6 -- .../custom_operations/custom_evaluators.hpp | 1 - .../custom_operations/custom_objects.hpp | 5 +- .../custom_operations/custom_operations.hpp | 13 +-- .../custom_operations_plugin.hpp | 2 +- .../wallet/include/graphene/wallet/wallet.hpp | 20 +--- libraries/wallet/wallet.cpp | 43 +-------- tests/cli/main.cpp | 12 +-- tests/custom_operations/main.cpp | 91 +++++++------------ 10 files changed, 52 insertions(+), 185 deletions(-) diff --git a/libraries/plugins/custom_operations/custom_evaluators.cpp b/libraries/plugins/custom_operations/custom_evaluators.cpp index 50eec94c96..f30e923145 100644 --- a/libraries/plugins/custom_operations/custom_evaluators.cpp +++ b/libraries/plugins/custom_operations/custom_evaluators.cpp @@ -65,7 +65,8 @@ vector custom_generic_evaluator::do_apply(const account_storage_ aso.catalog = op.catalog; aso.account = _account; aso.key = row.first; - aso.value = fc::json::from_string(row.second); + if(row.second.valid()) + aso.value = fc::json::from_string(*row.second); }); results.push_back(created.id); } @@ -75,7 +76,9 @@ vector custom_generic_evaluator::do_apply(const account_storage_ { try { _db->modify(*itr, [&op, this, &row](account_storage_object &aso) { - aso.value = fc::json::from_string(row.second); + aso.key = row.first; + if(row.second.valid()) + aso.value = fc::json::from_string(*row.second); }); results.push_back(itr->id); } @@ -85,42 +88,5 @@ vector custom_generic_evaluator::do_apply(const account_storage_ } return results; } -vector custom_generic_evaluator::do_apply(const account_storage_list& op) -{ - auto &index = _db->get_index_type().indices().get(); - vector results; - - if (op.remove) - { - for(auto const& list_value: op.values) { - - auto itr = index.find(make_tuple(_account, op.catalog, list_value)); - if(itr != index.end()) { - results.push_back(itr->id); - _db->remove(*itr); - } - } - } - else { - for(auto const& list_value: op.values) { - if(list_value.length() > 200) - { - dlog("List value can't be bigger than ${max} characters", ("max", CUSTOM_OPERATIONS_MAX_KEY_SIZE)); - continue; - } - auto itr = index.find(make_tuple(_account, op.catalog, list_value)); - if(itr == index.end()) - { - auto created = _db->create([&op, this, &list_value](account_storage_object &aso) { - aso.catalog = op.catalog; - aso.account = _account; - aso.key = list_value; - }); - results.push_back(itr->id); - } - } - } - return results; -} } } diff --git a/libraries/plugins/custom_operations/custom_operations.cpp b/libraries/plugins/custom_operations/custom_operations.cpp index 2e5bfd1c4d..5a351892ed 100644 --- a/libraries/plugins/custom_operations/custom_operations.cpp +++ b/libraries/plugins/custom_operations/custom_operations.cpp @@ -30,13 +30,7 @@ void account_storage_map::validate()const FC_ASSERT(key_values.size() <= 10); FC_ASSERT(catalog.length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE && catalog.length() > 0); } -void account_storage_list::validate()const -{ - FC_ASSERT(values.size() <= 10); - FC_ASSERT(catalog.length() <= CUSTOM_OPERATIONS_MAX_KEY_SIZE && catalog.length() > 0); -} } } //graphene::custom_operations GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) -GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp index 50d8644105..fe70545762 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_evaluators.hpp @@ -35,7 +35,6 @@ class custom_generic_evaluator custom_generic_evaluator(database& db, const account_id_type account); vector do_apply(const account_storage_map& o); - vector do_apply(const account_storage_list& o); }; } } diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp index 9b910f99d1..8586dc6e44 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_objects.hpp @@ -37,8 +37,7 @@ using namespace chain; #define CUSTOM_OPERATIONS_MAX_KEY_SIZE (200) enum types { - account_map = 0, - account_list = 1 + account_map = 0 }; struct account_storage_object : public abstract_object @@ -87,4 +86,4 @@ using account_storage_id_type = object_id key_values; - - void validate()const; -}; - -struct account_storage_list : chain::base_operation -{ - bool remove; - string catalog; - flat_set values; + flat_map> key_values; void validate()const; }; @@ -53,7 +44,5 @@ struct account_storage_list : chain::base_operation } } //graphene::custom_operations FC_REFLECT( graphene::custom_operations::account_storage_map, (remove)(catalog)(key_values) ) -FC_REFLECT( graphene::custom_operations::account_storage_list, (remove)(catalog)(values) ) GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_map ) -GRAPHENE_DECLARE_EXTERNAL_SERIALIZATION( graphene::custom_operations::account_storage_list ) diff --git a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp index cd75e565d6..39aec8ab07 100644 --- a/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp +++ b/libraries/plugins/custom_operations/include/graphene/custom_operations/custom_operations_plugin.hpp @@ -56,7 +56,7 @@ class custom_operations_plugin : public graphene::app::plugin std::unique_ptr my; }; -typedef fc::static_variant custom_plugin_operation; +typedef fc::static_variant custom_plugin_operation; struct custom_op_visitor { diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 6942733432..f8d622fbda 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2030,24 +2030,7 @@ class wallet_api * @return The signed transaction */ signed_transaction account_store_map(string account, string catalog, bool remove, - flat_map key_values, bool broadcast); - - /** - * Manage a accounts list(values)by using the custom operations plugin. - * - * Each account can optionally add and delete data from a dedicated list - * to be retrieved by any interested party. Can be used as a whitelist, address book, etc. - * - * @param account The account ID or name that we are adding additional information to. - * @param catalog The name of the catalog the operation will insert data to. - * @param remove true if you want to remove stuff from a catalog. - * @param values The list of strings to be inserted/removed to/from the catalog. - * @param broadcast true if you wish to broadcast the transaction - * - * @return The signed transaction - */ - signed_transaction account_store_list(string account, string catalog, bool remove, flat_set values, - bool broadcast); + flat_map> key_values, bool broadcast); /** * Get \c account_storage_object of an account by using the custom operations plugin. @@ -2270,7 +2253,6 @@ FC_API( graphene::wallet::wallet_api, (receive_blind_transfer) (get_order_book) (account_store_map) - (account_store_list) (get_account_storage) (quit) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 7c4ddfe232..01210f62ca 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1961,8 +1961,8 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (htlc_id)(issuer)(seconds_to_add)(broadcast) ) } - signed_transaction account_store_map(string account, string catalog, bool remove, flat_map key_values, - bool broadcast) + signed_transaction account_store_map(string account, string catalog, bool remove, + flat_map> key_values, bool broadcast) { try { @@ -1992,37 +1992,6 @@ class wallet_api_impl } FC_CAPTURE_AND_RETHROW( (account)(remove)(catalog)(key_values)(broadcast) ) } - signed_transaction account_store_list(string account, string catalog, bool remove, flat_set values, - bool broadcast) - { - try - { - FC_ASSERT( !self.is_locked() ); - - account_id_type account_id = get_account(account).id; - - custom_operation op; - account_storage_list store; - store.remove = remove; - store.catalog = catalog; - store.values = values; - - auto packed = fc::raw::pack(store); - packed.insert(packed.begin(), types::account_list); - - op.payer = account_id; - op.data = packed; - - signed_transaction tx; - tx.operations.push_back(op); - set_operation_fees( tx, _remote_db->get_global_properties().parameters.get_current_fees()); - tx.validate(); - - return sign_transaction(tx, broadcast); - - } FC_CAPTURE_AND_RETHROW( (account)(remove)(catalog)(values)(broadcast) ) - } - vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) { try { fc::optional vbid = maybe_id( account_name ); @@ -5252,17 +5221,11 @@ order_book wallet_api::get_order_book( const string& base, const string& quote, // custom operations signed_transaction wallet_api::account_store_map(string account, string catalog, bool remove, - flat_map key_values, bool broadcast) + flat_map> key_values, bool broadcast) { return my->account_store_map(account, catalog, remove, key_values, broadcast); } -signed_transaction wallet_api::account_store_list(string account, string catalog, bool remove, flat_set values, - bool broadcast) -{ - return my->account_store_list(account, catalog, remove, values, broadcast); -} - vector wallet_api::get_account_storage(string account, string catalog) { return my->_custom_operations->get_storage_info(account, catalog); diff --git a/tests/cli/main.cpp b/tests/cli/main.cpp index 8f8c82cd91..fc2703c932 100644 --- a/tests/cli/main.cpp +++ b/tests/cli/main.cpp @@ -1224,7 +1224,7 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_TEST_MESSAGE("Storing in a map."); - flat_map pairs; + flat_map> pairs; pairs["key1"] = fc::json::to_string("value1"); pairs["key2"] = fc::json::to_string("value2"); @@ -1249,12 +1249,12 @@ BOOST_FIXTURE_TEST_CASE( general_storage, cli_fixture ) BOOST_TEST_MESSAGE("Storing in a list."); - flat_set favs; - favs.insert("chocolate"); - favs.insert("milk"); - favs.insert("banana"); + flat_map> favs; + favs["chocolate"]; + favs["milk"]; + favs["banana"]; - con.wallet_api_ptr->account_store_list("nathan", "favourites", false, favs, true); + con.wallet_api_ptr->account_store_map("nathan", "favourites", false, favs, true); BOOST_TEST_MESSAGE("The system is generating a block."); BOOST_CHECK(generate_block(app1)); diff --git a/tests/custom_operations/main.cpp b/tests/custom_operations/main.cpp index 574263a087..9457e166e8 100644 --- a/tests/custom_operations/main.cpp +++ b/tests/custom_operations/main.cpp @@ -40,7 +40,7 @@ using namespace graphene::custom_operations; BOOST_FIXTURE_TEST_SUITE( custom_operation_tests, database_fixture ) -void map_operation(flat_map& pairs, bool remove, string& catalog, account_id_type& account, +void map_operation(flat_map>& pairs, bool remove, string& catalog, account_id_type& account, private_key& pk, database& db) { signed_transaction trx; @@ -65,31 +65,6 @@ void map_operation(flat_map& pairs, bool remove, string& catalog trx.clear(); } -void list_operation(flat_set& list, bool remove, string& catalog, account_id_type& account, - private_key& pk, database& db) -{ - signed_transaction trx; - set_expiration(db, trx); - - custom_operation op; - account_storage_list storage_list; - - storage_list.values = list; - storage_list.remove = remove; - storage_list.catalog = "contact_list"; - - auto packed = fc::raw::pack(storage_list); - packed.insert(packed.begin(), types::account_list); - - op.payer = account; - op.data = packed; - op.fee = db.get_global_properties().parameters.current_fees->calculate_fee(op); - trx.operations.push_back(op); - trx.sign(pk, db.get_chain_id()); - PUSH_TX(db, trx, ~0); - trx.clear(); -} - BOOST_AUTO_TEST_CASE(custom_operations_account_storage_map_test) { try { @@ -108,7 +83,7 @@ try { // catalog is indexed so cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) std::string catalog(201, 'a'); - flat_map pairs; + flat_map> pairs; pairs["key"] = fc::json::to_string("value"); map_operation(pairs, false, catalog, nathan_id, nathan_private_key, db); generate_block(); @@ -292,9 +267,9 @@ try { // catalog is indexed so cant be too big(greater than CUSTOM_OPERATIONS_MAX_KEY_SIZE(200) is not allowed) std::string catalog(201, 'a'); - flat_set accounts; - accounts.insert(robert.name); - list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + flat_map> accounts; + accounts[robert.name]; + map_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); auto storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); @@ -304,8 +279,8 @@ try { catalog = "whatever"; std::string value(201, 'a'); accounts.clear(); - accounts.insert(value); - list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + accounts[value]; + map_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); storage_results_nathan = custom_operations_api.get_storage_info("nathan", catalog); @@ -313,38 +288,38 @@ try { // nathan add a list of accounts to storage accounts.clear(); - accounts.insert(alice.name); - accounts.insert(robert.name); + accounts[alice.name]; + accounts[robert.name]; catalog = "contact_list"; - list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + map_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); // get the account list for nathan, check alice and robert are there storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, alice.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[1].key, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, robert.name); // add a value into account list already there accounts.clear(); - accounts.insert(alice.name); - list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + accounts[alice.name]; + map_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); // nothing changes storage_results_nathan = custom_operations_api.get_storage_info("nathan", "contact_list"); BOOST_CHECK_EQUAL(storage_results_nathan.size(), 2 ); BOOST_CHECK_EQUAL(storage_results_nathan[0].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[0].key, robert.name); + BOOST_CHECK_EQUAL(storage_results_nathan[0].key, alice.name); BOOST_CHECK_EQUAL(storage_results_nathan[1].account.instance.value, 16 ); - BOOST_CHECK_EQUAL(storage_results_nathan[1].key, alice.name); + BOOST_CHECK_EQUAL(storage_results_nathan[1].key, robert.name); // delete alice from the list accounts.clear(); - accounts.insert(alice.name); - list_operation(accounts, true, catalog, nathan_id, nathan_private_key, db); + accounts[alice.name]; + map_operation(accounts, true, catalog, nathan_id, nathan_private_key, db); generate_block(); // alice gone @@ -355,25 +330,25 @@ try { // add more than 10 accounts to the list in 1 operation is not allowed accounts.clear(); - accounts.insert("init0"); - accounts.insert("init1"); - accounts.insert("init2"); - accounts.insert("init3"); - accounts.insert("init4"); - accounts.insert("init5"); - accounts.insert("init6"); - accounts.insert("init7"); - accounts.insert("init8"); - accounts.insert("init9"); - accounts.insert("init10"); - list_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); + accounts["init0"]; + accounts["init1"]; + accounts["init2"]; + accounts["init3"]; + accounts["init4"]; + accounts["init5"]; + accounts["init6"]; + accounts["init7"]; + accounts["init8"]; + accounts["init9"]; + accounts["init10"]; + map_operation(accounts, false, catalog, nathan_id, nathan_private_key, db); generate_block(); // duplicated accounts in the list, only 1 will be inserted accounts.clear(); - accounts.insert(robert.name); - accounts.insert(robert.name); - list_operation(accounts, false, catalog, alice_id, alice_private_key, db); + accounts[robert.name]; + accounts[robert.name]; + map_operation(accounts, false, catalog, alice_id, alice_private_key, db); generate_block(); auto storage_results_alice = custom_operations_api.get_storage_info("alice", "contact_list"); From fe596cf98059ceac396790f5a6ad1f8d2b32d531 Mon Sep 17 00:00:00 2001 From: abitmore Date: Thu, 12 Sep 2019 15:52:50 -0400 Subject: [PATCH 069/534] Add HF-1669 macros --- libraries/chain/db_market.cpp | 4 ++-- libraries/chain/hardfork.d/CORE_1669.hf | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 libraries/chain/hardfork.d/CORE_1669.hf diff --git a/libraries/chain/db_market.cpp b/libraries/chain/db_market.cpp index 05c467eef3..4af3c6c810 100644 --- a/libraries/chain/db_market.cpp +++ b/libraries/chain/db_market.cpp @@ -54,9 +54,9 @@ namespace graphene { namespace chain { namespace detail { void database::globally_settle_asset( const asset_object& mia, const price& settlement_price ) { auto maint_time = get_dynamic_global_properties().next_maintenance_time; - bool before_core_hardfork_1270 = ( maint_time <= HARDFORK_CORE_1270_TIME ); // call price caching issue + bool before_core_hardfork_1669 = ( maint_time <= HARDFORK_CORE_1669_TIME ); // whether to use call_price - if( before_core_hardfork_1270 ) + if( before_core_hardfork_1669 ) { globally_settle_asset_impl( mia, settlement_price, get_index_type().indices().get() ); diff --git a/libraries/chain/hardfork.d/CORE_1669.hf b/libraries/chain/hardfork.d/CORE_1669.hf new file mode 100644 index 0000000000..e185ed52ee --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_1669.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #1669 Stop using call_price when globally settling +#ifndef HARDFORK_CORE_1669_TIME +#define HARDFORK_CORE_1669_TIME (fc::time_point_sec( 1600000000 )) // a temporary date in the future +#endif From 75b18686628994796e786aaa5047cdc50cd7c93d Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 12 Sep 2019 19:24:23 -0300 Subject: [PATCH 070/534] Delete Vagrantfile --- Vagrantfile | 112 ---------------------------------------------------- 1 file changed, 112 deletions(-) delete mode 100644 Vagrantfile diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index a47c45c060..0000000000 --- a/Vagrantfile +++ /dev/null @@ -1,112 +0,0 @@ -# Configures Ubuntu 14.04 VM to be used with BitShares 2.0 (Graphene) -# Downloads and builds all necessary software to run witness node and web GUI -# Use with Vagrant (http://docs.vagrantup.com/v2/getting-started/index.html) -# or just execute the shell script below. -# Vagrant setup supports the following providers: Virtual Box, Digital Ocean, Amazon EC2 - -$script = <