From 2e1f07d675898a96dc2f120f569705ab9a45e05c Mon Sep 17 00:00:00 2001 From: Alfredo Date: Sat, 7 Apr 2018 18:28:04 -0300 Subject: [PATCH 01/11] initial bsip35 --- libraries/chain/db_maint.cpp | 17 +- libraries/chain/hardfork.d/CORE_518.hf | 4 + tests/tests/smartcoin_tests.cpp | 355 +++++++++++++++++++++++++ 3 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 libraries/chain/hardfork.d/CORE_518.hf create mode 100644 tests/tests/smartcoin_tests.cpp diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 9e9ac0f349..eb10d1bad4 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -925,7 +925,22 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // Reset all BitAsset force settlement volumes to zero for( const auto& d : get_index_type().indices() ) { - modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); + if(head_block_time() < HARDFORK_CORE_518_TIME) + modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); + else { // clean expired feeds + modify( d, [this](asset_bitasset_data_object& o) { + o.force_settled_volume = 0; + // Remove all expired feeds + for( auto itr = o.feeds.begin(); itr != o.feeds.end();) + { + auto feed_time = itr[0].second.first; + if( feed_time + (o.options.feed_lifetime_sec) < head_block_time() && o.feeds.size() > o.options.minimum_feeds) + itr = o.feeds.erase(itr); + else + ++itr; + } + }); + } if( d.has_settlement() ) process_bids(d); } diff --git a/libraries/chain/hardfork.d/CORE_518.hf b/libraries/chain/hardfork.d/CORE_518.hf new file mode 100644 index 0000000000..72014667f7 --- /dev/null +++ b/libraries/chain/hardfork.d/CORE_518.hf @@ -0,0 +1,4 @@ +// bitshares-core issue #518 Clean up bitasset_data during maintenance +#ifndef HARDFORK_CORE_518_TIME +#define HARDFORK_CORE_518_TIME (fc::time_point_sec( 1600000000 )) +#endif \ No newline at end of file diff --git a/tests/tests/smartcoin_tests.cpp b/tests/tests/smartcoin_tests.cpp new file mode 100644 index 0000000000..6f1c8296b4 --- /dev/null +++ b/tests/tests/smartcoin_tests.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2018 oxarbitrage, and other 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 "../common/database_fixture.hpp" + +using namespace graphene::chain; +using namespace graphene::chain::test; + + +BOOST_FIXTURE_TEST_SUITE(smartcoin_tests, database_fixture) + + +BOOST_AUTO_TEST_CASE(bsip36) +{ + try + { + + /* Bug affects only smartcoions(market pegged assets feeded by active witnesses. + * Test case reproduces, advance to hardfork and check if solved after it. + */ + + /* References: + * BSIP 36: https://github.com/bitshares/bsips/blob/master/bsip-0036.md + * and the former: CORE Issue 518: https://github.com/bitshares/bitshares-core/issues/518 + */ + + // Create 12 accounts to be witnesses under our control + ACTORS( (witness0)(witness1)(witness2)(witness3)(witness4)(witness5) + (witness6)(witness7)(witness8)(witness9)(witness10)(witness11) ); + + // Upgrade all accounts to LTM + upgrade_to_lifetime_member(witness0_id); + upgrade_to_lifetime_member(witness1_id); + upgrade_to_lifetime_member(witness2_id); + upgrade_to_lifetime_member(witness3_id); + upgrade_to_lifetime_member(witness4_id); + upgrade_to_lifetime_member(witness5_id); + upgrade_to_lifetime_member(witness6_id); + upgrade_to_lifetime_member(witness7_id); + upgrade_to_lifetime_member(witness8_id); + upgrade_to_lifetime_member(witness9_id); + upgrade_to_lifetime_member(witness10_id); + upgrade_to_lifetime_member(witness11_id); + + // Create all the witnesses + const witness_id_type witness0_witness_id = create_witness(witness0_id, witness0_private_key).id; + const witness_id_type witness1_witness_id = create_witness(witness1_id, witness1_private_key).id; + const witness_id_type witness2_witness_id = create_witness(witness2_id, witness2_private_key).id; + const witness_id_type witness3_witness_id = create_witness(witness3_id, witness3_private_key).id; + const witness_id_type witness4_witness_id = create_witness(witness4_id, witness4_private_key).id; + const witness_id_type witness5_witness_id = create_witness(witness5_id, witness5_private_key).id; + const witness_id_type witness6_witness_id = create_witness(witness6_id, witness6_private_key).id; + const witness_id_type witness7_witness_id = create_witness(witness7_id, witness7_private_key).id; + const witness_id_type witness8_witness_id = create_witness(witness8_id, witness8_private_key).id; + const witness_id_type witness9_witness_id = create_witness(witness9_id, witness9_private_key).id; + const witness_id_type witness10_witness_id = create_witness(witness10_id, witness10_private_key).id; + const witness_id_type witness11_witness_id = create_witness(witness11_id, witness11_private_key).id; + + // Create a vector with private key of all witnesses, will be used to activate 11 witnesses at a time + const vector private_keys = { + witness0_private_key, + witness1_private_key, + witness2_private_key, + witness3_private_key, + witness4_private_key, + witness5_private_key, + witness6_private_key, + witness7_private_key, + witness8_private_key, + witness9_private_key, + witness10_private_key + }; + + // create a map with account id and witness id of the first 11 witnesses + const flat_map witness_map = { + {witness0_id, witness0_witness_id}, + {witness1_id, witness1_witness_id}, + {witness2_id, witness2_witness_id}, + {witness3_id, witness3_witness_id}, + {witness4_id, witness4_witness_id}, + {witness5_id, witness5_witness_id}, + {witness6_id, witness6_witness_id}, + {witness7_id, witness7_witness_id}, + {witness8_id, witness8_witness_id}, + {witness9_id, witness9_witness_id}, + {witness10_id, witness10_witness_id} + }; + + // Creare the asset + const asset_id_type bit_usd_id = create_bitasset("USDBIT").id; + + // Update the asset to be feeded by system witnesses + asset_update_operation op; + const asset_object &asset_obj = bit_usd_id(db); + op.asset_to_update = bit_usd_id; + op.issuer = asset_obj.issuer; + op.new_options = asset_obj.options; + op.new_options.flags &= witness_fed_asset; + op.new_options.issuer_permissions &= witness_fed_asset; + trx.operations.push_back(op); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.clear(); + + // Check current default witnesses, default chain is configured with 10 witnesses + auto witnesses = db.get_global_properties().active_witnesses; + BOOST_CHECK_EQUAL(witnesses.size(), 10); + BOOST_CHECK_EQUAL(witnesses.begin()[0].instance.value, 1); + BOOST_CHECK_EQUAL(witnesses.begin()[1].instance.value, 2); + BOOST_CHECK_EQUAL(witnesses.begin()[2].instance.value, 3); + BOOST_CHECK_EQUAL(witnesses.begin()[3].instance.value, 4); + BOOST_CHECK_EQUAL(witnesses.begin()[4].instance.value, 5); + BOOST_CHECK_EQUAL(witnesses.begin()[5].instance.value, 6); + BOOST_CHECK_EQUAL(witnesses.begin()[6].instance.value, 7); + BOOST_CHECK_EQUAL(witnesses.begin()[7].instance.value, 8); + BOOST_CHECK_EQUAL(witnesses.begin()[8].instance.value, 9); + BOOST_CHECK_EQUAL(witnesses.begin()[9].instance.value, 10); + + // We need to activate 11 witnesses by voting for each of them. + // Each witness is voted with incremental stake so last witness created will be the ones with more votes + + int c = 0; + for (auto l : witness_map) { + int stake = 100 + c + 1; + transfer(committee_account, l.first, asset(stake)); + { + account_update_operation op; + op.account = l.first; + op.new_options = l.first(db).options; + op.new_options->votes.insert(l.second(db).vote_id); + op.new_options->num_witness = std::count_if(op.new_options->votes.begin(), op.new_options->votes.end(), + [](vote_id_type id) { + return id.type() == vote_id_type::witness; + }); + trx.operations.push_back(op); + sign(trx, private_keys.at(c)); + PUSH_TX(db, trx); + trx.clear(); + } + ++c; + } + + // Trigger the new witnesses + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // Check my witnesses are now in control of the system + witnesses = db.get_global_properties().active_witnesses; + BOOST_CHECK_EQUAL(witnesses.size(), 11); + BOOST_CHECK_EQUAL(witnesses.begin()[0].instance.value, 11); + BOOST_CHECK_EQUAL(witnesses.begin()[1].instance.value, 12); + BOOST_CHECK_EQUAL(witnesses.begin()[2].instance.value, 13); + BOOST_CHECK_EQUAL(witnesses.begin()[3].instance.value, 14); + BOOST_CHECK_EQUAL(witnesses.begin()[4].instance.value, 15); + BOOST_CHECK_EQUAL(witnesses.begin()[5].instance.value, 16); + BOOST_CHECK_EQUAL(witnesses.begin()[6].instance.value, 17); + BOOST_CHECK_EQUAL(witnesses.begin()[7].instance.value, 18); + BOOST_CHECK_EQUAL(witnesses.begin()[8].instance.value, 19); + BOOST_CHECK_EQUAL(witnesses.begin()[9].instance.value, 20); + BOOST_CHECK_EQUAL(witnesses.begin()[10].instance.value, 21); + + // Adding 2 feeds with witnesses 0 and 1, checking if they get inserted + const asset_object &core = asset_id_type()(db); + price_feed feed; + feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); + publish_feed(bit_usd_id(db), witness0_id(db), feed); + + asset_bitasset_data_object bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + auto itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + + feed.settlement_price = bit_usd_id(db).amount(2) / core.amount(5); + publish_feed(bit_usd_id(db), witness1_id(db), feed); + + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 17); + + // Activate witness11 with voting stake, will kick the witness with less votes(witness0) out of the active list + transfer(committee_account, witness11_id, asset(121)); + set_expiration(db, trx); + { + account_update_operation op; + op.account = witness11_id; + op.new_options = witness11_id(db).options; + op.new_options->votes.insert(witness11_witness_id(db).vote_id); + op.new_options->num_witness = std::count_if(op.new_options->votes.begin(), op.new_options->votes.end(), + [](vote_id_type id) { + return id.type() == vote_id_type::witness; + }); + trx.operations.push_back(op); + sign(trx, witness11_private_key); + PUSH_TX(db, trx); + trx.clear(); + } + + // Trigger new witness + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // Check active witness list now + witnesses = db.get_global_properties().active_witnesses; + BOOST_CHECK_EQUAL(witnesses.begin()[0].instance.value, 12); + BOOST_CHECK_EQUAL(witnesses.begin()[1].instance.value, 13); + BOOST_CHECK_EQUAL(witnesses.begin()[2].instance.value, 14); + BOOST_CHECK_EQUAL(witnesses.begin()[3].instance.value, 15); + BOOST_CHECK_EQUAL(witnesses.begin()[4].instance.value, 16); + BOOST_CHECK_EQUAL(witnesses.begin()[5].instance.value, 17); + BOOST_CHECK_EQUAL(witnesses.begin()[6].instance.value, 18); + BOOST_CHECK_EQUAL(witnesses.begin()[7].instance.value, 19); + BOOST_CHECK_EQUAL(witnesses.begin()[8].instance.value, 20); + BOOST_CHECK_EQUAL(witnesses.begin()[9].instance.value, 21); + BOOST_CHECK_EQUAL(witnesses.begin()[10].instance.value, 22); + + // witness0 has been removed but it was a feeder before + // Feed persist in the blockchain, this reproduces the issue + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + + // Feed persist after expiration + const auto feed_lifetime = bit_usd_id(db).bitasset_data(db).options.feed_lifetime_sec; + generate_blocks(db.head_block_time() + feed_lifetime + 1); + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + + // Other witnesses add more feeds + feed.settlement_price = bit_usd_id(db).amount(4) / core.amount(5); + publish_feed(bit_usd_id(db), witness2_id(db), feed); + feed.settlement_price = bit_usd_id(db).amount(3) / core.amount(5); + publish_feed(bit_usd_id(db), witness3_id(db), feed); + + // But the one from witness0 is never removed + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 4); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + + // Feed from witness1 is also expired but never deleted + // Only 1 feed is needed as default minimum_feeds = 1 + const auto minimum_feeds = bit_usd_id(db).bitasset_data(db).options.minimum_feeds; + BOOST_CHECK_EQUAL(minimum_feeds, 1); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 17); + + // Advancing into HF time + generate_blocks(HARDFORK_CORE_518_TIME); + + // Advancing to next maint + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // Feed for witness1 is deleted, expired feeds are deleted, last feed is kept + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 19); + + // Even if expired, last feed will persist(correct behaviour) + generate_blocks(db.head_block_time() + feed_lifetime + 1); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 19); + + // Reactivate witness0 + transfer(committee_account, witness0_id, asset(100)); + set_expiration(db, trx); + { + account_update_operation op; + op.account = witness0_id; + op.new_options = witness0_id(db).options; + op.new_options->votes.insert(witness0_witness_id(db).vote_id); + op.new_options->num_witness = std::count_if(op.new_options->votes.begin(), op.new_options->votes.end(), + [](vote_id_type id) { + return id.type() == vote_id_type::witness; + }); + trx.operations.push_back(op); + sign(trx, witness0_private_key); + PUSH_TX(db, trx); + trx.clear(); + } + + // This will deactivate witness1 as it is the one with less votes + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // Checking + witnesses = db.get_global_properties().active_witnesses; + BOOST_CHECK_EQUAL(witnesses.begin()[0].instance.value, 11); + BOOST_CHECK_EQUAL(witnesses.begin()[1].instance.value, 13); + BOOST_CHECK_EQUAL(witnesses.begin()[2].instance.value, 14); + BOOST_CHECK_EQUAL(witnesses.begin()[3].instance.value, 15); + BOOST_CHECK_EQUAL(witnesses.begin()[4].instance.value, 16); + BOOST_CHECK_EQUAL(witnesses.begin()[5].instance.value, 17); + BOOST_CHECK_EQUAL(witnesses.begin()[6].instance.value, 18); + BOOST_CHECK_EQUAL(witnesses.begin()[7].instance.value, 19); + BOOST_CHECK_EQUAL(witnesses.begin()[8].instance.value, 20); + BOOST_CHECK_EQUAL(witnesses.begin()[9].instance.value, 21); + BOOST_CHECK_EQUAL(witnesses.begin()[10].instance.value, 22); + + // witness0 start feed producing again + feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); + publish_feed(bit_usd_id(db), witness0_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 19); + + // Make feed from witnes3 expire + generate_blocks(itr[1].second.first + feed_lifetime + 1); + + // In next maint only feed from witness0 will persist + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + + } FC_LOG_AND_RETHROW() +} +BOOST_AUTO_TEST_SUITE_END() From 10c7e8f63f4e41a1e8d1b0284930f72286984e5b Mon Sep 17 00:00:00 2001 From: Alfredo Date: Mon, 9 Apr 2018 10:06:35 -0300 Subject: [PATCH 02/11] add update_feed_producers test --- tests/tests/smartcoin_tests.cpp | 97 ++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/tests/tests/smartcoin_tests.cpp b/tests/tests/smartcoin_tests.cpp index 6f1c8296b4..42430fe3f9 100644 --- a/tests/tests/smartcoin_tests.cpp +++ b/tests/tests/smartcoin_tests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 oxarbitrage, and other contributors. + * Copyright (c) 2018 oxarbitrage, and contributors. * * The MIT License * @@ -352,4 +352,99 @@ BOOST_AUTO_TEST_CASE(bsip36) } FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(bsip36_update_feed_producers) +{ + try + { + /* For MPA feeded by non witnesses feeds can always be cleaned with asset_update_feed_producers_operation */ + /* Still, if the op is never executed, the fix after HF will delete expired not needed feeds at maint time */ + ACTORS( (sam)(alice)(paul)(bob) ); + + // Create the asset + const asset_id_type bit_usd_id = create_bitasset("USDBIT").id; + + // Update asset issuer + const asset_object &asset_obj = bit_usd_id(db); + { + asset_update_operation op; + op.asset_to_update = bit_usd_id; + op.issuer = asset_obj.issuer; + op.new_issuer = bob_id; + op.new_options = asset_obj.options; + op.new_options.flags &= ~witness_fed_asset; + trx.operations.push_back(op); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.clear(); + } + + // Add 3 feed producers for asset + { + asset_update_feed_producers_operation op; + op.asset_to_update = bit_usd_id; + op.issuer = bob_id; + op.new_feed_producers = {sam_id, alice_id, paul_id}; + trx.operations.push_back(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx); + generate_block(); + trx.clear(); + } + + // Bitshares will create entiries in the field feed after feed producer + auto bitasset_data = bit_usd_id(db).bitasset_data(db); + + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 3); + auto itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 17); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 18); + + // Removing a feed producer + { + asset_update_feed_producers_operation op; + op.asset_to_update = bit_usd_id; + op.issuer = bob_id; + op.new_feed_producers = {alice_id, paul_id}; + trx.operations.push_back(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx); + generate_block(); + trx.clear(); + } + + // Feed for removed producer is removed + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 18); + + // Feed persist after expiration + const auto feed_lifetime = bit_usd_id(db).bitasset_data(db).options.feed_lifetime_sec; + generate_blocks(db.head_block_time() + feed_lifetime + 1); + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 18); + + // Advancing into HF time + generate_blocks(HARDFORK_CORE_518_TIME); + + // Advancing to next maint + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // Expired feed is deleted, only 1(min_feeds) is kept + bitasset_data = bit_usd_id(db).bitasset_data(db); + itr = bitasset_data.feeds.begin(); + + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 18); + + } FC_LOG_AND_RETHROW() +} + + BOOST_AUTO_TEST_SUITE_END() From 101a02c422527fa8834c9c4e530a269cf75c3258 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Thu, 26 Apr 2018 20:12:26 -0300 Subject: [PATCH 03/11] change bsip code to only affect smartcoins --- libraries/chain/db_maint.cpp | 22 +- .../include/graphene/chain/asset_object.hpp | 2 + tests/tests/smartcoin_tests.cpp | 252 +++++++++++++++--- 3 files changed, 237 insertions(+), 39 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index eb10d1bad4..cf1a985336 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -930,14 +930,20 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g else { // clean expired feeds modify( d, [this](asset_bitasset_data_object& o) { o.force_settled_volume = 0; - // Remove all expired feeds - for( auto itr = o.feeds.begin(); itr != o.feeds.end();) - { - auto feed_time = itr[0].second.first; - if( feed_time + (o.options.feed_lifetime_sec) < head_block_time() && o.feeds.size() > o.options.minimum_feeds) - itr = o.feeds.erase(itr); - else - ++itr; + + // Check if asset is smartcoin + const auto& idx = get_index_type().indices().get(); + auto itr = idx.find(o.id); + auto flags = itr->options.flags; + + if((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + for (auto itr = o.feeds.begin(); itr != o.feeds.end();) { // loop feeds + auto feed_time = itr->second.first; + if (feed_time + (o.options.feed_lifetime_sec) < head_block_time()) + itr = o.feeds.erase(itr); // delete expired feed + else + ++itr; + } } }); } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index a337152bf6..867d06bd8e 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -228,11 +228,13 @@ namespace graphene { namespace chain { struct by_symbol; struct by_type; struct by_issuer; + struct by_bitasset_id; typedef multi_index_container< asset_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, ordered_unique< tag, member >, + ordered_unique< tag, member, &asset_object::bitasset_data_id> >, ordered_non_unique< tag, member >, ordered_unique< tag, composite_key< asset_object, diff --git a/tests/tests/smartcoin_tests.cpp b/tests/tests/smartcoin_tests.cpp index 42430fe3f9..a9d23f1332 100644 --- a/tests/tests/smartcoin_tests.cpp +++ b/tests/tests/smartcoin_tests.cpp @@ -43,8 +43,7 @@ BOOST_AUTO_TEST_CASE(bsip36) { try { - - /* Bug affects only smartcoions(market pegged assets feeded by active witnesses. + /* Bug affects only smartcoions(market pegged assets feeded by active witnesses or committee members). * Test case reproduces, advance to hardfork and check if solved after it. */ @@ -115,10 +114,10 @@ BOOST_AUTO_TEST_CASE(bsip36) {witness10_id, witness10_witness_id} }; - // Creare the asset + // Create the asset const asset_id_type bit_usd_id = create_bitasset("USDBIT").id; - // Update the asset to be feeded by system witnesses + // Update the asset to be fed by system witnesses asset_update_operation op; const asset_object &asset_obj = bit_usd_id(db); op.asset_to_update = bit_usd_id; @@ -147,7 +146,6 @@ BOOST_AUTO_TEST_CASE(bsip36) // We need to activate 11 witnesses by voting for each of them. // Each witness is voted with incremental stake so last witness created will be the ones with more votes - int c = 0; for (auto l : witness_map) { int stake = 100 + c + 1; @@ -270,7 +268,7 @@ BOOST_AUTO_TEST_CASE(bsip36) BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); // Feed from witness1 is also expired but never deleted - // Only 1 feed is needed as default minimum_feeds = 1 + // All feeds should be deleted at this point const auto minimum_feeds = bit_usd_id(db).bitasset_data(db).options.minimum_feeds; BOOST_CHECK_EQUAL(minimum_feeds, 1); BOOST_CHECK_EQUAL(itr[1].first.instance.value, 17); @@ -281,20 +279,53 @@ BOOST_AUTO_TEST_CASE(bsip36) // Advancing to next maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - // Feed for witness1 is deleted, expired feeds are deleted, last feed is kept + // All expired feeds are deleted + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 0); + + // witness1 start feed producing again + feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); + publish_feed(bit_usd_id(db), witness1_id(db), feed); bitasset_data = bit_usd_id(db).bitasset_data(db); BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); + + // generate some blocks up to expiration but feed will not be deleted yet as need next maint time + generate_blocks(itr[0].second.first + feed_lifetime + 1); + + // add another feed with witness2 + feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); + publish_feed(bit_usd_id(db), witness2_id(db), feed); bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); itr = bitasset_data.feeds.begin(); - BOOST_CHECK_EQUAL(itr[0].first.instance.value, 19); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 18); - // Even if expired, last feed will persist(correct behaviour) - generate_blocks(db.head_block_time() + feed_lifetime + 1); + // make the first feed expire + generate_blocks(itr[0].second.first + feed_lifetime + 1); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // feed from witness0 expires and gets deleted, feed from witness is on time so persist bitasset_data = bit_usd_id(db).bitasset_data(db); BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 18); + + // expire everything + generate_blocks(itr[0].second.first + feed_lifetime + 1); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 0); + + // add new feed with witness1 + feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); + publish_feed(bit_usd_id(db), witness1_id(db), feed); bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); itr = bitasset_data.feeds.begin(); - BOOST_CHECK_EQUAL(itr[0].first.instance.value, 19); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); // Reactivate witness0 transfer(committee_account, witness0_id, asset(100)); @@ -331,24 +362,17 @@ BOOST_AUTO_TEST_CASE(bsip36) BOOST_CHECK_EQUAL(witnesses.begin()[9].instance.value, 21); BOOST_CHECK_EQUAL(witnesses.begin()[10].instance.value, 22); - // witness0 start feed producing again - feed.settlement_price = bit_usd_id(db).amount(1) / core.amount(5); - publish_feed(bit_usd_id(db), witness0_id(db), feed); - bitasset_data = bit_usd_id(db).bitasset_data(db); - BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + // feed from witness1 is still here as the witness is no longer a producer but the feed is not yet expired + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); itr = bitasset_data.feeds.begin(); - BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); - BOOST_CHECK_EQUAL(itr[1].first.instance.value, 19); - - // Make feed from witnes3 expire - generate_blocks(itr[1].second.first + feed_lifetime + 1); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); - // In next maint only feed from witness0 will persist + // make feed from witness1 expire + generate_blocks(itr[0].second.first + feed_lifetime + 1); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + bitasset_data = bit_usd_id(db).bitasset_data(db); - BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); - itr = bitasset_data.feeds.begin(); - BOOST_CHECK_EQUAL(itr[0].first.instance.value, 16); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 0); } FC_LOG_AND_RETHROW() } @@ -357,8 +381,7 @@ BOOST_AUTO_TEST_CASE(bsip36_update_feed_producers) { try { - /* For MPA feeded by non witnesses feeds can always be cleaned with asset_update_feed_producers_operation */ - /* Still, if the op is never executed, the fix after HF will delete expired not needed feeds at maint time */ + /* For MPA fed by non witnesses or non committee mmembers but by feed producers changes should do nothing */ ACTORS( (sam)(alice)(paul)(bob) ); // Create the asset @@ -392,7 +415,7 @@ BOOST_AUTO_TEST_CASE(bsip36_update_feed_producers) trx.clear(); } - // Bitshares will create entiries in the field feed after feed producer + // Bitshares will create entries in the field feed after feed producers are added auto bitasset_data = bit_usd_id(db).bitasset_data(db); BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 3); @@ -436,15 +459,182 @@ BOOST_AUTO_TEST_CASE(bsip36_update_feed_producers) // Advancing to next maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - // Expired feed is deleted, only 1(min_feeds) is kept + // Expired feeds persist, no changes bitasset_data = bit_usd_id(db).bitasset_data(db); itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 17); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 18); + + } FC_LOG_AND_RETHROW() +} +BOOST_AUTO_TEST_CASE(bsip36_additional) +{ + try + { + /* Check impact of bsip36 with multiple feeds */ + INVOKE( bsip36 ); + + // get the stuff needed from invoked test + const asset_id_type bit_usd_id = get_asset("USDBIT").id; + const asset_id_type core_id = asset_id_type(); + const account_id_type witness5_id= get_account("witness5").id; + const account_id_type witness6_id= get_account("witness6").id; + const account_id_type witness7_id= get_account("witness7").id; + const account_id_type witness8_id= get_account("witness8").id; + const account_id_type witness9_id= get_account("witness9").id; + const account_id_type witness10_id= get_account("witness10").id; + + + set_expiration( db, trx ); + + // changing lifetime feed to 5 days + // maint interval default is every 1 day + { + asset_update_bitasset_operation op; + op.new_options.minimum_feeds = 3; + op.new_options.feed_lifetime_sec = 86400 * 5; + op.asset_to_update = bit_usd_id; + op.issuer = bit_usd_id(db).issuer; + trx.operations.push_back(op); + PUSH_TX(db, trx, ~0); + generate_block(); + trx.clear(); + } + + price_feed feed; + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness5_id(db), feed); + auto bitasset_data = bit_usd_id(db).bitasset_data(db); BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 1); - BOOST_CHECK_EQUAL(itr[0].first.instance.value, 18); + auto itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness6_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 22); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness7_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 3); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 22); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 23); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness8_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 4); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 22); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 23); + BOOST_CHECK_EQUAL(itr[3].first.instance.value, 24); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness9_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 5); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 22); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 23); + BOOST_CHECK_EQUAL(itr[3].first.instance.value, 24); + BOOST_CHECK_EQUAL(itr[4].first.instance.value, 25); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness10_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 6); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 22); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 23); + BOOST_CHECK_EQUAL(itr[3].first.instance.value, 24); + BOOST_CHECK_EQUAL(itr[4].first.instance.value, 25); + BOOST_CHECK_EQUAL(itr[5].first.instance.value, 26); + + // make the older feed expire + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 5); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 22); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 23); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 24); + BOOST_CHECK_EQUAL(itr[3].first.instance.value, 25); + BOOST_CHECK_EQUAL(itr[4].first.instance.value, 26); + + // make older 2 feeds expire + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 3); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 24); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 25); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 26); + + // witness5 add new feed, feeds are sorted by witness_id not by feed_time + feed.settlement_price = bit_usd_id(db).amount(1) / core_id(db).amount(5); + publish_feed(bit_usd_id(db), witness5_id(db), feed); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 4); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 24); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 25); + BOOST_CHECK_EQUAL(itr[3].first.instance.value, 26); + + // another feed expires + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 3); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[1].first.instance.value, 25); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 26); + + // another feed expires + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_block(); + bitasset_data = bit_usd_id(db).bitasset_data(db); + BOOST_CHECK_EQUAL(bitasset_data.feeds.size(), 2); + itr = bitasset_data.feeds.begin(); + BOOST_CHECK_EQUAL(itr[0].first.instance.value, 21); + BOOST_CHECK_EQUAL(itr[2].first.instance.value, 26); + + // and so on } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_SUITE_END() From 63199d08660eb19dcbce0f6fa4340f484d941258 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 27 Apr 2018 11:25:23 -0300 Subject: [PATCH 04/11] get asset_id from first feed instead of index tag --- libraries/chain/db_maint.cpp | 23 ++++++++++--------- .../include/graphene/chain/asset_object.hpp | 2 -- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index cf1a985336..3092252f0d 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -932,17 +932,18 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g o.force_settled_volume = 0; // Check if asset is smartcoin - const auto& idx = get_index_type().indices().get(); - auto itr = idx.find(o.id); - auto flags = itr->options.flags; - - if((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin - for (auto itr = o.feeds.begin(); itr != o.feeds.end();) { // loop feeds - auto feed_time = itr->second.first; - if (feed_time + (o.options.feed_lifetime_sec) < head_block_time()) - itr = o.feeds.erase(itr); // delete expired feed - else - ++itr; + const auto& settlement_price = o.feeds.begin()->second.second.settlement_price; + if(!settlement_price.is_null()) { + const auto &asset = get(settlement_price.base.asset_id); + auto flags = asset.options.flags; + if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + for (auto itr = o.feeds.begin(); itr != o.feeds.end();) { // loop feeds + auto feed_time = itr->second.first; + if (feed_time + (o.options.feed_lifetime_sec) < head_block_time()) + itr = o.feeds.erase(itr); // delete expired feed + else + ++itr; + } } } }); diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 867d06bd8e..a337152bf6 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -228,13 +228,11 @@ namespace graphene { namespace chain { struct by_symbol; struct by_type; struct by_issuer; - struct by_bitasset_id; typedef multi_index_container< asset_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, ordered_unique< tag, member >, - ordered_unique< tag, member, &asset_object::bitasset_data_id> >, ordered_non_unique< tag, member >, ordered_unique< tag, composite_key< asset_object, From f60a9530924c23b9fd0416f8653d87620e0739e5 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 27 Apr 2018 18:43:30 -0300 Subject: [PATCH 05/11] fix performance and some errors --- libraries/chain/db_maint.cpp | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 3092252f0d..bf19abe07f 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -922,27 +922,37 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g d.accounts_registered_this_interval = 0; }); + // check HF_518 + bool hf518 = false; + if(head_block_time() >= HARDFORK_CORE_518_TIME) + hf518 = true; + // Reset all BitAsset force settlement volumes to zero for( const auto& d : get_index_type().indices() ) { - if(head_block_time() < HARDFORK_CORE_518_TIME) + if(!hf518) modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); else { // clean expired feeds modify( d, [this](asset_bitasset_data_object& o) { o.force_settled_volume = 0; // Check if asset is smartcoin - const auto& settlement_price = o.feeds.begin()->second.second.settlement_price; - if(!settlement_price.is_null()) { - const auto &asset = get(settlement_price.base.asset_id); - auto flags = asset.options.flags; - if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin - for (auto itr = o.feeds.begin(); itr != o.feeds.end();) { // loop feeds - auto feed_time = itr->second.first; - if (feed_time + (o.options.feed_lifetime_sec) < head_block_time()) - itr = o.feeds.erase(itr); // delete expired feed - else - ++itr; + if(o.feeds.size() > 0) { + const auto &settlement_price = o.feeds.begin()->second.second.settlement_price; + if (!settlement_price.is_null()) { + const auto &asset = get(settlement_price.base.asset_id); + auto flags = asset.options.flags; + if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + if(std::numeric_limits::max() - o.options.feed_lifetime_sec > + head_block_time().sec_since_epoch()) { // check overflow + fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; + for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds + auto feed_time = itr->second.first; + std::advance(itr, 1); + if (feed_time < calculate) + o.feeds.erase(itr.base()); // delete expired feed + } + } } } } From 67e1ec438ec90a1aad67330c9aae56c2e6c5dae1 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 27 Apr 2018 19:53:36 -0300 Subject: [PATCH 06/11] change hardfork structure --- libraries/chain/db_maint.cpp | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index bf19abe07f..516b996c75 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -922,29 +922,20 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g d.accounts_registered_this_interval = 0; }); - // check HF_518 - bool hf518 = false; - if(head_block_time() >= HARDFORK_CORE_518_TIME) - hf518 = true; - - // Reset all BitAsset force settlement volumes to zero - for( const auto& d : get_index_type().indices() ) - { - if(!hf518) - modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); - else { // clean expired feeds - modify( d, [this](asset_bitasset_data_object& o) { - o.force_settled_volume = 0; - + if(head_block_time() >= HARDFORK_CORE_518_TIME) { + for( const auto& d : get_index_type().indices() ) { + modify(d, [this](asset_bitasset_data_object &o) { + o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero // Check if asset is smartcoin - if(o.feeds.size() > 0) { + if (o.feeds.size() > 0) { const auto &settlement_price = o.feeds.begin()->second.second.settlement_price; if (!settlement_price.is_null()) { const auto &asset = get(settlement_price.base.asset_id); auto flags = asset.options.flags; if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin - if(std::numeric_limits::max() - o.options.feed_lifetime_sec > - head_block_time().sec_since_epoch()) { // check overflow + // check overflow + if (std::numeric_limits::max() - o.options.feed_lifetime_sec > + head_block_time().sec_since_epoch()) { fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds auto feed_time = itr->second.first; @@ -957,9 +948,16 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g } } }); + if (d.has_settlement()) + process_bids(d); + } + } + else { + for( const auto& d : get_index_type().indices() ) { + modify(d, [](asset_bitasset_data_object &o) { o.force_settled_volume = 0; }); + if (d.has_settlement()) + process_bids(d); } - if( d.has_settlement() ) - process_bids(d); } // process_budget needs to run at the bottom because From c93913c2dbf68f148827665581c52cf1c6b8c14a Mon Sep 17 00:00:00 2001 From: Alfredo Date: Sat, 28 Apr 2018 11:07:02 -0300 Subject: [PATCH 07/11] move code of bsip to new function --- libraries/chain/db_maint.cpp | 79 ++++++++++--------- .../chain/include/graphene/chain/database.hpp | 1 + 2 files changed, 43 insertions(+), 37 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 516b996c75..8bca5797f4 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -766,6 +766,47 @@ void database::process_bids( const asset_bitasset_data_object& bad ) _cancel_bids_and_revive_mpa( to_revive, bad ); } +void database::process_bitassets() +{ + if(head_block_time() >= HARDFORK_CORE_518_TIME) { + for( const auto& d : get_index_type().indices() ) { + modify(d, [this](asset_bitasset_data_object &o) { + o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero + // Check if asset is smartcoin + if (o.feeds.size() > 0) { + const auto &settlement_price = o.feeds.begin()->second.second.settlement_price; + if (!settlement_price.is_null()) { + const auto &asset = get(settlement_price.base.asset_id); + auto flags = asset.options.flags; + if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + // check overflow + if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) { + fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; + for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds + auto feed_time = itr->second.first; + std::advance(itr, 1); + if (feed_time < calculate) + o.feeds.erase(itr.base()); // delete expired feed + } + } + } + } + } + }); + if (d.has_settlement()) + process_bids(d); + } + } + else { + for( const auto& d : get_index_type().indices() ) { + // Reset all BitAsset force settlement volumes to zero + modify(d, [](asset_bitasset_data_object &o) { o.force_settled_volume = 0; }); + if (d.has_settlement()) + process_bids(d); + } + } +} + void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) { const auto& gpo = get_global_properties(); @@ -922,43 +963,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g d.accounts_registered_this_interval = 0; }); - if(head_block_time() >= HARDFORK_CORE_518_TIME) { - for( const auto& d : get_index_type().indices() ) { - modify(d, [this](asset_bitasset_data_object &o) { - o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero - // Check if asset is smartcoin - if (o.feeds.size() > 0) { - const auto &settlement_price = o.feeds.begin()->second.second.settlement_price; - if (!settlement_price.is_null()) { - const auto &asset = get(settlement_price.base.asset_id); - auto flags = asset.options.flags; - if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin - // check overflow - if (std::numeric_limits::max() - o.options.feed_lifetime_sec > - head_block_time().sec_since_epoch()) { - fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; - for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds - auto feed_time = itr->second.first; - std::advance(itr, 1); - if (feed_time < calculate) - o.feeds.erase(itr.base()); // delete expired feed - } - } - } - } - } - }); - if (d.has_settlement()) - process_bids(d); - } - } - else { - for( const auto& d : get_index_type().indices() ) { - modify(d, [](asset_bitasset_data_object &o) { o.force_settled_volume = 0; }); - if (d.has_settlement()) - process_bids(d); - } - } + process_bitassets(); // process_budget needs to run at the bottom because // it needs to know the next_maintenance_time diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 133dc1c4b9..85845edbe4 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -467,6 +467,7 @@ namespace graphene { namespace chain { void update_active_committee_members(); void update_worker_votes(); void process_bids( const asset_bitasset_data_object& bad ); + void process_bitassets(); template void perform_account_maintenance(std::tuple helpers); From 09b7ffb1ed59ae5446242b7da77ec3c4ac002047 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Sat, 28 Apr 2018 21:20:57 -0300 Subject: [PATCH 08/11] add asset_id to bitasset object --- libraries/chain/asset_evaluator.cpp | 6 +++-- libraries/chain/db_maint.cpp | 27 ++++++++----------- .../include/graphene/chain/asset_object.hpp | 4 +++ 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/libraries/chain/asset_evaluator.cpp b/libraries/chain/asset_evaluator.cpp index 9c7ac0cd62..c6012f6a94 100644 --- a/libraries/chain/asset_evaluator.cpp +++ b/libraries/chain/asset_evaluator.cpp @@ -131,14 +131,16 @@ object_id_type asset_create_evaluator::do_apply( const asset_create_operation& o } asset_bitasset_data_id_type bit_asset_id; + + auto next_asset_id = db().get_index_type().get_next_id(); + if( op.bitasset_opts.valid() ) bit_asset_id = db().create( [&]( asset_bitasset_data_object& a ) { a.options = *op.bitasset_opts; a.is_prediction_market = op.is_prediction_market; + a.asset_id = next_asset_id; }).id; - auto next_asset_id = db().get_index_type().get_next_id(); - const asset_object& new_asset = db().create( [&]( asset_object& a ) { a.issuer = op.issuer; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 8bca5797f4..a8265db3a6 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -773,22 +773,17 @@ void database::process_bitassets() modify(d, [this](asset_bitasset_data_object &o) { o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero // Check if asset is smartcoin - if (o.feeds.size() > 0) { - const auto &settlement_price = o.feeds.begin()->second.second.settlement_price; - if (!settlement_price.is_null()) { - const auto &asset = get(settlement_price.base.asset_id); - auto flags = asset.options.flags; - if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin - // check overflow - if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) { - fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; - for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds - auto feed_time = itr->second.first; - std::advance(itr, 1); - if (feed_time < calculate) - o.feeds.erase(itr.base()); // delete expired feed - } - } + const auto &asset = get(o.asset_id); + auto flags = asset.options.flags; + if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + // check overflow + if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) { + fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; + for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds + auto feed_time = itr->second.first; + std::advance(itr, 1); + if (feed_time < calculate) + o.feeds.erase(itr.base()); // delete expired feed } } } diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index a337152bf6..08672ec1e5 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -171,6 +171,9 @@ namespace graphene { namespace chain { static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_asset_bitasset_data_type; + /// The asset this object belong to + asset_id_type asset_id; + /// The tunable options for BitAssets are stored in this field. bitasset_options options; @@ -250,6 +253,7 @@ FC_REFLECT_DERIVED( graphene::chain::asset_dynamic_data_object, (graphene::db::o (current_supply)(confidential_supply)(accumulated_fees)(fee_pool) ) FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db::object), + (asset_id) (feeds) (current_feed) (current_feed_publication_time) From bcea8655a78b1cecd381f4a12672eec5fde0d8c2 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Mon, 30 Apr 2018 10:28:29 -0300 Subject: [PATCH 09/11] change coding style --- libraries/chain/db_maint.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index a8265db3a6..550fa84bd5 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -768,18 +768,24 @@ void database::process_bids( const asset_bitasset_data_object& bad ) void database::process_bitassets() { - if(head_block_time() >= HARDFORK_CORE_518_TIME) { - for( const auto& d : get_index_type().indices() ) { - modify(d, [this](asset_bitasset_data_object &o) { + if(head_block_time() >= HARDFORK_CORE_518_TIME) + { + for( const auto& d : get_index_type().indices() ) + { + modify(d, [this](asset_bitasset_data_object &o) + { o.force_settled_volume = 0; // Reset all BitAsset force settlement volumes to zero - // Check if asset is smartcoin + const auto &asset = get(o.asset_id); auto flags = asset.options.flags; - if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) { // if smartcoin + if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) // if smartcoin + { // check overflow - if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) { + if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) + { fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; - for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) { // loop feeds + for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) // loop feeds + { auto feed_time = itr->second.first; std::advance(itr, 1); if (feed_time < calculate) @@ -793,7 +799,8 @@ void database::process_bitassets() } } else { - for( const auto& d : get_index_type().indices() ) { + for( const auto& d : get_index_type().indices() ) + { // Reset all BitAsset force settlement volumes to zero modify(d, [](asset_bitasset_data_object &o) { o.force_settled_volume = 0; }); if (d.has_settlement()) From 81bdfa3a7c64e2763ac36f6b98458edc7d11540e Mon Sep 17 00:00:00 2001 From: Alfredo Date: Wed, 2 May 2018 19:42:17 -0300 Subject: [PATCH 10/11] typo fix --- libraries/chain/hardfork.d/CORE_518.hf | 2 +- tests/tests/smartcoin_tests.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/hardfork.d/CORE_518.hf b/libraries/chain/hardfork.d/CORE_518.hf index 72014667f7..429716c20f 100644 --- a/libraries/chain/hardfork.d/CORE_518.hf +++ b/libraries/chain/hardfork.d/CORE_518.hf @@ -1,4 +1,4 @@ // bitshares-core issue #518 Clean up bitasset_data during maintenance #ifndef HARDFORK_CORE_518_TIME #define HARDFORK_CORE_518_TIME (fc::time_point_sec( 1600000000 )) -#endif \ No newline at end of file +#endif diff --git a/tests/tests/smartcoin_tests.cpp b/tests/tests/smartcoin_tests.cpp index a9d23f1332..ffa80f7551 100644 --- a/tests/tests/smartcoin_tests.cpp +++ b/tests/tests/smartcoin_tests.cpp @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(bsip36) { try { - /* Bug affects only smartcoions(market pegged assets feeded by active witnesses or committee members). + /* Issue affects only smartcoins(market pegged assets feeded by active witnesses or committee members). * Test case reproduces, advance to hardfork and check if solved after it. */ From 960bfe91659cfcd0803bc3e20b78448d7a4be316 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Wed, 2 May 2018 20:14:14 -0300 Subject: [PATCH 11/11] change overflow test --- libraries/chain/db_maint.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 550fa84bd5..d342513222 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -778,20 +778,19 @@ void database::process_bitassets() const auto &asset = get(o.asset_id); auto flags = asset.options.flags; - if ((flags & witness_fed_asset) || (flags & committee_fed_asset)) // if smartcoin + if ( (flags & witness_fed_asset || flags & committee_fed_asset) && + (o.options.feed_lifetime_sec < head_block_time().sec_since_epoch()) ) // if smartcoin && check overflow { - // check overflow - if (std::numeric_limits::max() - o.options.feed_lifetime_sec > head_block_time().sec_since_epoch()) + + fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; + for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) // loop feeds { - fc::time_point_sec calculate = head_block_time() - o.options.feed_lifetime_sec; - for (auto itr = o.feeds.rbegin(); itr != o.feeds.rend();) // loop feeds - { - auto feed_time = itr->second.first; - std::advance(itr, 1); - if (feed_time < calculate) - o.feeds.erase(itr.base()); // delete expired feed - } + auto feed_time = itr->second.first; + std::advance(itr, 1); + if (feed_time < calculate) + o.feeds.erase(itr.base()); // delete expired feed } + } }); if (d.has_settlement())