diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 2a8b5019f9..e2d0ca5eb2 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -378,54 +378,55 @@ void check_children_of_bitasset(database& d, const asset_update_bitasset_operati return; // loop through all assets that have this asset as a backing asset - const auto& idx = d.get_index_type().indices().get(); - - for( auto itr = idx.lower_bound(true); itr != idx.end(); ++itr ) - { - const auto& child = *itr; - if ( child.bitasset_data(d).options.short_backing_asset == op.asset_to_update ) - { - if ( after_hf_922_931 ) + const auto& idx = d.get_index_type() + .indices() + .get(); + auto backed_range = idx.equal_range(op.asset_to_update); + std::for_each( backed_range.first, backed_range.second, + [after_hf_922_931, &new_backing_asset, &d, &op](const asset_bitasset_data_object& bitasset_data) { - FC_ASSERT( child.get_id() != op.new_options.short_backing_asset, - "A BitAsset would be invalidated by changing this backing asset ('A' backed by 'B' backed by 'A')." ); + const auto& child = bitasset_data.asset_id(d); + if ( after_hf_922_931 ) + { + FC_ASSERT( child.get_id() != op.new_options.short_backing_asset, + "A BitAsset would be invalidated by changing this backing asset ('A' backed by 'B' backed by 'A')." ); - FC_ASSERT( child.issuer != GRAPHENE_COMMITTEE_ACCOUNT, - "A blockchain-controlled market asset would be invalidated by changing this backing asset." ); + FC_ASSERT( child.issuer != GRAPHENE_COMMITTEE_ACCOUNT, + "A blockchain-controlled market asset would be invalidated by changing this backing asset." ); - FC_ASSERT( !new_backing_asset.is_market_issued(), - "A non-blockchain controlled BitAsset would be invalidated by changing this backing asset."); + FC_ASSERT( !new_backing_asset.is_market_issued(), + "A non-blockchain controlled BitAsset would be invalidated by changing this backing asset."); - } - else - { - if( child.get_id() == op.new_options.short_backing_asset ) - { - wlog( "Before hf-922-931, modified an asset to be backed by another, but would cause a continuous " - "loop. A cannot be backed by B which is backed by A." ); - return; - } - - if( child.issuer == GRAPHENE_COMMITTEE_ACCOUNT ) - { - wlog( "before hf-922-931, modified an asset to be backed by a non-CORE, but this asset " - "is a backing asset for a committee-issued asset. This occurred at block ${b}", - ("b", d.head_block_num())); - return; } else { - if ( new_backing_asset.is_market_issued() ) { // a.k.a. !UIA - wlog( "before hf-922-931, modified an asset to be backed by an MPA, but this asset " - "is a backing asset for another MPA, which would cause MPA backed by MPA backed by MPA. " - "This occurred at block ${b}", + if( child.get_id() == op.new_options.short_backing_asset ) + { + wlog( "Before hf-922-931, modified an asset to be backed by another, but would cause a continuous " + "loop. A cannot be backed by B which is backed by A." ); + return; + } + + if( child.issuer == GRAPHENE_COMMITTEE_ACCOUNT ) + { + wlog( "before hf-922-931, modified an asset to be backed by a non-CORE, but this asset " + "is a backing asset for a committee-issued asset. This occurred at block ${b}", ("b", d.head_block_num())); return; } - } // if child.issuer - } // if hf 922/931 - } // if this child is backed by the asset being adjusted - } // for each asset + else + { + if ( new_backing_asset.is_market_issued() ) // a.k.a. !UIA + { + wlog( "before hf-922-931, modified an asset to be backed by an MPA, but this asset " + "is a backing asset for another MPA, which would cause MPA backed by MPA backed by MPA. " + "This occurred at block ${b}", + ("b", d.head_block_num())); + return; + } + } // if child.issuer + } // if hf 922/931 + } ); // end of lambda and std::for_each() } // check_children_of_bitasset void_result asset_update_bitasset_evaluator::do_evaluate(const asset_update_bitasset_operation& op) diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 0e37b8664a..4491c3ad32 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -232,10 +232,22 @@ namespace graphene { namespace chain { void update_median_feeds(time_point_sec current_time); }; + // key extractor for short backing asset + struct bitasset_short_backing_asset_extractor + { + typedef asset_id_type result_type; + result_type operator() (const asset_bitasset_data_object& obj) const + { + return obj.options.short_backing_asset; + } + }; + + struct by_short_backing_asset; typedef multi_index_container< asset_bitasset_data_object, indexed_by< - ordered_unique< tag, member< object, object_id_type, &object::id > > + ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_non_unique< tag, bitasset_short_backing_asset_extractor > > > asset_bitasset_data_object_multi_index_type; typedef generic_index asset_bitasset_data_index; diff --git a/tests/common/database_fixture.hpp b/tests/common/database_fixture.hpp index 4c98f78adf..48dd6b3f6b 100644 --- a/tests/common/database_fixture.hpp +++ b/tests/common/database_fixture.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -150,18 +151,18 @@ extern uint32_t GRAPHENE_TESTING_GENESIS_TIMESTAMP; #define PREP_ACTOR(name) \ fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \ - public_key_type name ## _public_key = name ## _private_key.get_public_key(); \ + graphene::chain::public_key_type name ## _public_key = name ## _private_key.get_public_key(); \ BOOST_CHECK( name ## _public_key != public_key_type() ); #define ACTOR(name) \ PREP_ACTOR(name) \ const auto& name = create_account(BOOST_PP_STRINGIZE(name), name ## _public_key); \ - account_id_type name ## _id = name.id; (void)name ## _id; + graphene::chain::account_id_type name ## _id = name.id; (void)name ## _id; #define GET_ACTOR(name) \ fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \ const account_object& name = get_account(BOOST_PP_STRINGIZE(name)); \ - account_id_type name ## _id = name.id; \ + graphene::chain::account_id_type name ## _id = name.id; \ (void)name ##_id #define ACTORS_IMPL(r, data, elem) ACTOR(elem) diff --git a/tests/tests/bitasset_tests.cpp b/tests/tests/bitasset_tests.cpp index bcb4366e70..9e9a2814ed 100644 --- a/tests/tests/bitasset_tests.cpp +++ b/tests/tests/bitasset_tests.cpp @@ -25,6 +25,7 @@ #include #include + #include #include @@ -80,7 +81,7 @@ void change_backing_asset(database_fixture& fixture, const fc::ecc::private_key& } /****** - * @ brief helper method to turn witness_fed_asset on and off + * @brief helper method to turn witness_fed_asset on and off * @param fixture the database_fixture * @param new_issuer optionally change the issuer * @param signing_key signer @@ -115,6 +116,27 @@ void change_asset_options(database_fixture& fixture, const optionalcreate_bitasset( "USDBIT", GRAPHENE_COMMITTEE_ACCOUNT ); + asset_objs.bit_usd = fixture->create_bitasset( "USDBIT", GRAPHENE_COMMITTEE_ACCOUNT ).get_id(); BOOST_TEST_MESSAGE( "Create USDBACKED" ); - asset_objs.bit_usdbacked = &fixture->create_bitasset( "USDBACKED", GRAPHENE_COMMITTEE_ACCOUNT, - 100, charge_market_fee, 2, asset_objs.bit_usd->get_id() ); + asset_objs.bit_usdbacked = fixture->create_bitasset( "USDBACKED", GRAPHENE_COMMITTEE_ACCOUNT, + 100, charge_market_fee, 2, asset_objs.bit_usd ).get_id(); BOOST_TEST_MESSAGE( "Create USDBACKEDII" ); - asset_objs.bit_usdbacked2 = &fixture->create_bitasset( "USDBACKEDII", GRAPHENE_WITNESS_ACCOUNT, - 100, charge_market_fee, 2, asset_objs.bit_usd->get_id() ); + asset_objs.bit_usdbacked2 = fixture->create_bitasset( "USDBACKEDII", GRAPHENE_WITNESS_ACCOUNT, + 100, charge_market_fee, 2, asset_objs.bit_usd ).get_id(); BOOST_TEST_MESSAGE( "Create PARENT" ); - asset_objs.bit_parent = &fixture->create_bitasset( "PARENT", GRAPHENE_WITNESS_ACCOUNT); + asset_objs.bit_parent = fixture->create_bitasset( "PARENT", GRAPHENE_WITNESS_ACCOUNT).get_id(); BOOST_TEST_MESSAGE( "Create CHILDUSER" ); - asset_objs.bit_child_bitasset = &fixture->create_bitasset( "CHILDUSER", GRAPHENE_WITNESS_ACCOUNT, - 100, charge_market_fee, 2, asset_objs.bit_parent->get_id() ); + asset_objs.bit_child_bitasset = fixture->create_bitasset( "CHILDUSER", GRAPHENE_WITNESS_ACCOUNT, + 100, charge_market_fee, 2, asset_objs.bit_parent ).get_id(); BOOST_TEST_MESSAGE( "Create user issued USERISSUED" ); - asset_objs.user_issued = &fixture->create_user_issued_asset( "USERISSUED", - GRAPHENE_WITNESS_ACCOUNT(fixture->db), charge_market_fee ); + asset_objs.user_issued = fixture->create_user_issued_asset( "USERISSUED", + GRAPHENE_WITNESS_ACCOUNT(fixture->db), charge_market_fee ).get_id(); BOOST_TEST_MESSAGE( "Create a user-issued asset with a precision of 6" ); - asset_objs.six_precision = &fixture->create_user_issued_asset( "SIXPRECISION", GRAPHENE_WITNESS_ACCOUNT(fixture->db), - charge_market_fee, price(asset(1, asset_id_type(1)), asset(1)), 6 ); + asset_objs.six_precision = fixture->create_user_issued_asset( "SIXPRECISION", GRAPHENE_WITNESS_ACCOUNT(fixture->db), + charge_market_fee, price(asset(1, asset_id_type(1)), asset(1)), 6 ).get_id(); BOOST_TEST_MESSAGE( "Create Prediction market with precision of 6, backed by SIXPRECISION" ); - asset_objs.prediction = &fixture->create_prediction_market( "PREDICTION", GRAPHENE_WITNESS_ACCOUNT, - 100, charge_market_fee, 6, asset_objs.six_precision->get_id() ); + asset_objs.prediction = fixture->create_prediction_market( "PREDICTION", GRAPHENE_WITNESS_ACCOUNT, + 100, charge_market_fee, 6, asset_objs.six_precision ).get_id(); return asset_objs; } @@ -611,15 +633,15 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) ACTORS( (nathan) (john) ); assets_922_931 asset_objs = create_assets_922_931( this ); - const asset_id_type bit_usd_id = asset_objs.bit_usd->get_id(); + const asset_id_type bit_usd_id = asset_objs.bit_usd; // make a generic operation bitasset_evaluator_wrapper evaluator; evaluator.set_db(db); asset_update_bitasset_operation op; op.asset_to_update = bit_usd_id; - op.issuer = asset_objs.bit_usd->issuer; - op.new_options = asset_objs.bit_usd->bitasset_data(db).options; + op.issuer = asset_objs.bit_usd(db).issuer; + op.new_options = asset_objs.bit_usd(db).bitasset_data(db).options; // this should pass BOOST_TEST_MESSAGE( "Evaluating a good operation" ); @@ -627,7 +649,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // test with a market issued asset BOOST_TEST_MESSAGE( "Sending a non-bitasset." ); - op.asset_to_update = asset_objs.user_issued->get_id(); + op.asset_to_update = asset_objs.user_issued; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "on a non-BitAsset." ); op.asset_to_update = bit_usd_id; @@ -657,19 +679,19 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // 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->get_id(); - op.issuer = asset_objs.prediction->issuer; + op.asset_to_update = asset_objs.prediction; + op.issuer = asset_objs.prediction(db).issuer; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); op.asset_to_update = bit_usd_id; - op.issuer = asset_objs.bit_usd->issuer; + 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->get_id(); + op.new_options.short_backing_asset = asset_objs.six_precision; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); 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->get_id(); + op.new_options.short_backing_asset = asset_objs.prediction; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); op.new_options.short_backing_asset = correct_asset_id; @@ -678,30 +700,30 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // because that will make CHILD be backed by an asset that is not itself backed by CORE or a UIA. BOOST_TEST_MESSAGE( "Message should contain: but this asset is a backing asset for another MPA, which would cause MPA " "backed by MPA backed by MPA." ); - op.asset_to_update = asset_objs.bit_parent->get_id(); - op.issuer = asset_objs.bit_parent->issuer; - op.new_options.short_backing_asset = asset_objs.bit_usdbacked->get_id(); + op.asset_to_update = asset_objs.bit_parent; + 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() ); // 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->get_id(); + op.new_options.short_backing_asset = asset_objs.user_issued; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); // 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->get_id(); + op.new_options.short_backing_asset = asset_objs.bit_child_bitasset; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); - op.new_options.short_backing_asset = asset_objs.user_issued->get_id(); + 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 // Cannot change PARENT's backing asset from CORE to something else because that will make CHILD be backed by // an asset that is not itself backed by CORE create_bitasset( "CHILDCOMMITTEE", GRAPHENE_COMMITTEE_ACCOUNT, 100, charge_market_fee, 2, - asset_objs.bit_parent->get_id() ); + 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() ); - op.asset_to_update = asset_objs.bit_usd->get_id(); - op.issuer = asset_objs.bit_usd->issuer; + 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; // USDBACKED is backed by USDBIT (which is backed by CORE) @@ -710,13 +732,13 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_before_922_931 ) // because that would be a MPA backed by MPA backed by MPA. BOOST_TEST_MESSAGE( "Message should contain: a BitAsset cannot be backed by a BitAsset that " "itself is backed by a BitAsset." ); - op.asset_to_update = asset_objs.bit_usdbacked2->get_id(); - op.issuer = asset_objs.bit_usdbacked2->issuer; - op.new_options.short_backing_asset = asset_objs.bit_usdbacked->get_id(); + 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() ); // set everything to a more normal state - op.asset_to_update = asset_objs.bit_usdbacked->get_id(); - op.issuer = asset_objs.bit_usd->issuer; + op.asset_to_update = asset_objs.bit_usdbacked; + op.issuer = asset_objs.bit_usd(db).issuer; op.new_options.short_backing_asset = asset_id_type(); // Feed lifetime must exceed block interval @@ -757,15 +779,15 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) ACTORS( (nathan) (john) ); assets_922_931 asset_objs = create_assets_922_931( this ); - const asset_id_type& bit_usd_id = asset_objs.bit_usd->get_id(); + const asset_id_type& bit_usd_id = asset_objs.bit_usd; // make a generic operation bitasset_evaluator_wrapper evaluator; evaluator.set_db( db ); asset_update_bitasset_operation op; op.asset_to_update = bit_usd_id; - op.issuer = asset_objs.bit_usd->issuer; - op.new_options = asset_objs.bit_usd->bitasset_data(db).options; + op.issuer = asset_objs.bit_usd(db).issuer; + op.new_options = asset_objs.bit_usd(db).bitasset_data(db).options; // this should pass BOOST_TEST_MESSAGE( "Evaluating a good operation" ); @@ -773,7 +795,7 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // test with a market issued asset BOOST_TEST_MESSAGE( "Sending a non-bitasset." ); - op.asset_to_update = asset_objs.user_issued->get_id(); + op.asset_to_update = asset_objs.user_issued; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "Cannot update BitAsset-specific settings on a non-BitAsset" ); op.asset_to_update = bit_usd_id; @@ -803,17 +825,17 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // prediction market with different precision BOOST_TEST_MESSAGE( "Prediction market with different precision" ); - op.asset_to_update = asset_objs.prediction->get_id(); - op.issuer = asset_objs.prediction->issuer; + op.asset_to_update = asset_objs.prediction; + op.issuer = asset_objs.prediction(db).issuer; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "The precision of the asset and backing asset must" ); op.asset_to_update = bit_usd_id; - op.issuer = asset_objs.bit_usd->issuer; + op.issuer = asset_objs.bit_usd(db).issuer; // checking old backing asset instead of new backing asset BOOST_TEST_MESSAGE( "Correctly checking new backing asset rather than old backing asset" ); - op.new_options.short_backing_asset = asset_objs.six_precision->get_id(); + op.new_options.short_backing_asset = asset_objs.six_precision; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "which is not market issued asset nor CORE." ); - op.new_options.short_backing_asset = asset_objs.prediction->get_id(); + op.new_options.short_backing_asset = asset_objs.prediction; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "which is not backed by CORE" ); op.new_options.short_backing_asset = correct_asset_id; @@ -821,29 +843,30 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // Cannot change PARENT's backing asset from CORE to something that is not [CORE | UIA] // because that will make CHILD be backed by an asset that is not itself backed by CORE or a UIA. BOOST_TEST_MESSAGE( "Attempting to change PARENT to be backed by a non-core and non-user-issued asset" ); - op.asset_to_update = asset_objs.bit_parent->get_id(); - op.issuer = asset_objs.bit_parent->issuer; - op.new_options.short_backing_asset = asset_objs.bit_usdbacked->get_id(); + op.asset_to_update = asset_objs.bit_parent; + op.issuer = asset_objs.bit_parent(db).issuer; + op.new_options.short_backing_asset = asset_objs.bit_usdbacked; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "A non-blockchain controlled BitAsset would be invalidated" ); // 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->get_id(); + op.new_options.short_backing_asset = asset_objs.user_issued; BOOST_CHECK( evaluator.evaluate(op) == void_result() ); // 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->get_id(); + 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->get_id(); + op.new_options.short_backing_asset = asset_objs.user_issued; + BOOST_CHECK( evaluator.evaluate(op) == void_result() ); 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 CHILD be backed by - // an asset that is not itself backed by CORE + // Cannot change PARENT's backing asset from CORE to something else because that will make CHILDCOMMITTEE + // be backed by an asset that is not itself backed by CORE create_bitasset( "CHILDCOMMITTEE", GRAPHENE_COMMITTEE_ACCOUNT, 100, charge_market_fee, 2, - asset_objs.bit_parent->get_id() ); + asset_objs.bit_parent ); // it should again not work REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "A blockchain-controlled market asset would be invalidated" ); - op.asset_to_update = asset_objs.bit_usd->get_id(); - op.issuer = asset_objs.bit_usd->issuer; + 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; // USDBACKED is backed by USDBIT (which is backed by CORE) @@ -851,14 +874,14 @@ BOOST_AUTO_TEST_CASE( bitasset_evaluator_test_after_922_931 ) // We should not be able to make USDBACKEDII be backed by USDBACKED // because that would be a MPA backed by MPA backed by MPA. BOOST_TEST_MESSAGE( "MPA -> MPA -> MPA not allowed" ); - op.asset_to_update = asset_objs.bit_usdbacked2->get_id(); - op.issuer = asset_objs.bit_usdbacked2->issuer; - op.new_options.short_backing_asset = asset_objs.bit_usdbacked->get_id(); + 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; REQUIRE_EXCEPTION_WITH_TEXT( evaluator.evaluate(op), "A BitAsset cannot be backed by a BitAsset that itself is backed by a BitAsset" ); // set everything to a more normal state - op.asset_to_update = asset_objs.bit_usdbacked->get_id(); - op.issuer = asset_objs.bit_usd->issuer; + op.asset_to_update = asset_objs.bit_usdbacked; + op.issuer = asset_objs.bit_usd(db).issuer; op.new_options.short_backing_asset = asset_id_type(); // Feed lifetime must exceed block interval @@ -1109,6 +1132,81 @@ BOOST_AUTO_TEST_CASE( hf_935_test ) } } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( bitasset_secondary_index ) +{ + ACTORS( (nathan) ); + + graphene::chain::asset_id_type core_id; + BOOST_TEST_MESSAGE( "Running test bitasset_secondary_index" ); + BOOST_TEST_MESSAGE( "Core asset id: " + fc::json::to_pretty_string( core_id ) ); + BOOST_TEST_MESSAGE("Create coins"); + try + { + // make 5 coins (backed by core) + for(int i = 0; i < 5; i++) + { + create_bitasset_backed(*this, i, core_id, nathan_private_key); + } + // make the next 5 (10-14) be backed by COIN1 + graphene::chain::asset_id_type coin1_id = get_asset("COIN1TEST").get_id(); + for(int i = 5; i < 10; i++) + { + create_bitasset_backed(*this, i, coin1_id, nathan_private_key); + } + // make the next 5 (15-19) be backed by COIN2 + graphene::chain::asset_id_type coin2_id = get_asset("COIN2TEST").get_id(); + for(int i = 10; i < 15; i++) + { + create_bitasset_backed(*this, i, coin2_id, nathan_private_key); + } + // make the last 5 be backed by core + for(int i = 15; i < 20; i++) + { + create_bitasset_backed(*this, i, core_id, nathan_private_key); + } + + BOOST_TEST_MESSAGE("Searching for all coins backed by CORE"); + const auto& idx = db.get_index_type().indices().get(); + auto core_itr = idx.equal_range( core_id ); + BOOST_TEST_MESSAGE("Searching for all coins backed by COIN1"); + auto coin1_itr = idx.equal_range( coin1_id ); + BOOST_TEST_MESSAGE("Searching for all coins backed by COIN2"); + auto coin2_itr = idx.equal_range( coin2_id ); + + int core_count = 0, coin1_count = 0, coin2_count = 0; + + BOOST_TEST_MESSAGE("Counting coins in each category"); + + for( auto itr = core_itr.first ; itr != core_itr.second; ++itr) + { + BOOST_CHECK(itr->options.short_backing_asset == core_id); + BOOST_TEST_MESSAGE( fc::json::to_pretty_string(itr->asset_id) + " is backed by CORE" ); + core_count++; + } + for( auto itr = coin1_itr.first ; itr != coin1_itr.second; ++itr ) + { + BOOST_CHECK(itr->options.short_backing_asset == coin1_id); + BOOST_TEST_MESSAGE( fc::json::to_pretty_string( itr->asset_id) + " is backed by COIN1TEST" ); + coin1_count++; + } + for( auto itr = coin2_itr.first; itr != coin2_itr.second; ++itr ) + { + BOOST_CHECK(itr->options.short_backing_asset == coin2_id); + BOOST_TEST_MESSAGE( fc::json::to_pretty_string( itr->asset_id) + " is backed by COIN2TEST" ); + coin2_count++; + } + + BOOST_CHECK( core_count >= 10 ); + BOOST_CHECK_EQUAL( coin1_count, 5 ); + BOOST_CHECK_EQUAL( coin2_count, 5 ); + } + catch (fc::exception& ex) + { + BOOST_FAIL(ex.to_string(fc::log_level(fc::log_level::all))); + } +} + + /***** * @brief make sure feeds work correctly after changing from non-witness-fed to witness-fed before the 868 fork * NOTE: This test case is a different issue than what is currently being worked on, and fails. Hopefully it