From 66c9606652f8edc571033a5e4a7a3bbbd146ef61 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 1 Jul 2015 17:18:49 -0400 Subject: [PATCH] Progress #17: Add assets, initial witness count to genesis state --- libraries/app/application.cpp | 4 +- libraries/chain/account_object.cpp | 2 +- libraries/chain/db_init.cpp | 208 +++++++++++++----- libraries/chain/db_witness_schedule.cpp | 2 +- .../include/graphene/chain/asset_object.hpp | 36 +-- .../chain/include/graphene/chain/database.hpp | 60 +---- .../chain/include/graphene/chain/types.hpp | 4 +- tests/common/database_fixture.cpp | 4 +- tests/tests/block_tests.cpp | 4 +- 9 files changed, 177 insertions(+), 147 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 592040c4..0cadcf74 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -165,8 +165,8 @@ namespace detail { nathan_key.get_public_key(), nathan_key.get_public_key(), true); - initial_state.initial_committee.push_back({name}); - initial_state.initial_witnesses.push_back({name, nathan_key.get_public_key(), secret}); + initial_state.initial_committee_candidates.push_back({name}); + initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key(), secret}); } initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key()); diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index de923898..b3917fc2 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -96,7 +96,7 @@ void account_statistics_object::process_fees(const account_object& a, database& share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage); share_type referral = core_fee_total - network_cut - lifetime_cut; - d.modify(dynamic_asset_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) { + d.modify(asset_dynamic_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) { d.accumulated_fees += network_cut; }); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index bc27d34a..b62a3c89 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -53,9 +53,10 @@ #include #include - #include +#include + namespace graphene { namespace chain { void database::initialize_evaluators() @@ -146,7 +147,7 @@ void database::initialize_indexes() void database::init_genesis(const genesis_state_type& genesis_state) { try { - FC_ASSERT(genesis_state.initial_witnesses.size() > 0, + FC_ASSERT(genesis_state.initial_witness_candidates.size() > 0, "Cannot start a chain with zero witnesses."); _undo_db.disable(); @@ -259,40 +260,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) }); create([&](block_summary_object&) {}); - // Create initial balances - const auto& asset_idx = get_index_type().indices().get(); - share_type total_allocation = 0; - if( !genesis_state.initial_balances.empty() ) - { - for( const auto& handout : genesis_state.initial_balances ) - { - create([&handout,&asset_idx,total_allocation](balance_object& b) { - b.balance = asset(handout.amount, asset_idx.find(handout.asset_symbol)->get_id()); - b.owner = handout.owner; - }); - total_allocation += handout.amount; - } - } - - // Create initial vesting balances - if( !genesis_state.initial_vesting_balances.empty() ) - { - for( const genesis_state_type::initial_vesting_balance_type& vest : genesis_state.initial_vesting_balances ) - { - create([&](balance_object& b) { - b.balance = asset(vest.amount, asset_idx.find(vest.asset_symbol)->get_id()); - b.owner = vest.owner; - linear_vesting_policy policy; - policy.earliest_withdraw_time = vest.earliest_withdrawal_date; - policy.begin_date = vest.vesting_start_date; - policy.vesting_seconds = (vest.vesting_end_date - vest.vesting_start_date).to_seconds(); - policy.begin_balance = b.balance.amount; - b.vesting_policy = policy; - }); - total_allocation += vest.amount; - } - } - // Create initial accounts if( !genesis_state.initial_accounts.empty() ) { @@ -300,17 +267,17 @@ void database::init_genesis(const genesis_state_type& genesis_state) { key_id_type key_id = apply_operation(genesis_eval_state, key_create_operation({asset(), - committee_account.id, + GRAPHENE_TEMP_ACCOUNT, account.owner_key})).get(); account_create_operation cop; cop.name = account.name; - cop.registrar = account_id_type(1); + cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, key_id, 1); if( account.owner_key != account.active_key ) { key_id = apply_operation(genesis_eval_state, key_create_operation({asset(), - committee_account.id, + GRAPHENE_TEMP_ACCOUNT, account.owner_key})).get(); cop.active = authority(1, key_id, 1); } else { @@ -328,6 +295,126 @@ void database::init_genesis(const genesis_state_type& genesis_state) } } } + const auto& accounts_by_name = get_index_type().indices().get(); + auto get_account_id = [&accounts_by_name](const string& name) { + auto itr = accounts_by_name.find(name); + FC_ASSERT(itr != accounts_by_name.end()); + return itr->get_id(); + }; + + // Create initial assets + const auto& assets_by_symbol = get_index_type().indices().get(); + auto get_asset_id = [&assets_by_symbol](const string& symbol) { + auto itr = assets_by_symbol.find(symbol); + FC_ASSERT(itr != assets_by_symbol.end()); + return itr->get_id(); + }; + if( !genesis_state.initial_assets.empty() ) + { + for( const genesis_state_type::initial_asset_type& asset : genesis_state.initial_assets ) + { + asset_dynamic_data_id_type dynamic_data_id; + optional bitasset_data_id; + if( asset.bitasset_options.valid() ) + { + share_type total_allocated; + asset_id_type new_asset_id = get_index_type().get_next_id(); + asset_id_type collateral_asset_id = get_asset_id(asset.bitasset_options->backing_asset_symbol); + + int collateral_holder_number = 0; + for( const auto& collateral_rec : asset.bitasset_options->collateral_records ) + { + key_id_type key_id = apply_operation(genesis_eval_state, + key_create_operation{{}, + GRAPHENE_TEMP_ACCOUNT, + collateral_rec.owner}).get(); + account_create_operation cop; + cop.name = asset.symbol + "-collateral-holder-" + std::to_string(collateral_holder_number); + boost::algorithm::to_lower(cop.name); + cop.registrar = GRAPHENE_TEMP_ACCOUNT; + cop.owner = authority(1, key_id, 1); + cop.active = cop.owner; + account_id_type owner_account_id = apply_operation(genesis_eval_state, cop).get(); + + create([&](call_order_object& c) { + c.borrower = owner_account_id; + c.collateral = collateral_rec.collateral; + c.debt = collateral_rec.debt; + c.call_price = price::call_price(chain::asset(c.debt, new_asset_id), + chain::asset(c.collateral, collateral_asset_id), + asset.bitasset_options->maintenance_collateral_ratio); + }); + + total_allocated += collateral_rec.debt; + } + + bitasset_data_id = create([&](asset_bitasset_data_object& b) { + b.options.feed_lifetime_sec = asset.bitasset_options->feed_lifetime_sec; + b.options.minimum_feeds = asset.bitasset_options->minimum_feeds; + b.options.force_settlement_delay_sec = asset.bitasset_options->force_settlement_delay_sec; + b.options.force_settlement_offset_percent = asset.bitasset_options->force_settlement_offset_percent; + b.options.maximum_force_settlement_volume = asset.bitasset_options->maximum_force_settlement_volume; + b.options.short_backing_asset = get_asset_id(asset.bitasset_options->backing_asset_symbol); + }).id; + + dynamic_data_id = create([&](asset_dynamic_data_object& d) { + d.current_supply = total_allocated; + d.accumulated_fees = asset.initial_accumulated_fees; + }).id; + } else + dynamic_data_id = create([&](asset_dynamic_data_object& d) { + d.accumulated_fees = asset.initial_accumulated_fees; + }).id; + + create([&](asset_object& a) { + a.symbol = asset.symbol; + a.options.description = asset.description; + a.precision = asset.precision; + a.issuer = get_account_id(asset.issuer_name); + a.options.max_supply = asset.max_supply; + a.options.market_fee_percent = asset.market_fee_percent; + a.options.max_market_fee = asset.max_market_fee; + a.options.issuer_permissions = asset.issuer_permissions; + a.options.flags = asset.flags; + + a.dynamic_asset_data_id = dynamic_data_id; + a.bitasset_data_id = bitasset_data_id; + }); + } + } + + // Create initial balances + share_type total_allocation; + if( !genesis_state.initial_balances.empty() ) + { + for( const auto& handout : genesis_state.initial_balances ) + { + create([&handout,&assets_by_symbol,total_allocation](balance_object& b) { + b.balance = asset(handout.amount, assets_by_symbol.find(handout.asset_symbol)->get_id()); + b.owner = handout.owner; + }); + total_allocation += handout.amount; + } + } + + // Create initial vesting balances + if( !genesis_state.initial_vesting_balances.empty() ) + { + for( const genesis_state_type::initial_vesting_balance_type& vest : genesis_state.initial_vesting_balances ) + { + create([&](balance_object& b) { + b.balance = asset(vest.amount, assets_by_symbol.find(vest.asset_symbol)->get_id()); + b.owner = vest.owner; + linear_vesting_policy policy; + policy.earliest_withdraw_time = vest.earliest_withdrawal_date; + policy.begin_date = vest.vesting_start_date; + policy.vesting_seconds = (vest.vesting_end_date - vest.vesting_start_date).to_seconds(); + policy.begin_balance = b.balance.amount; + b.vesting_policy = policy; + }); + total_allocation += vest.amount; + } + } // Set current supply based on allocations, if they happened if( total_allocation > 0 ) @@ -338,39 +425,36 @@ void database::init_genesis(const genesis_state_type& genesis_state) adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{})); } - flat_set init_delegates; - flat_set init_witnesses; - const auto& accounts_by_name = get_index_type().indices().get(); - // Create initial witnesses and delegates - std::for_each(genesis_state.initial_witnesses.begin(), genesis_state.initial_witnesses.end(), + std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { - const account_object& witness_account = *accounts_by_name.find(witness.owner_name); - const key_object& signing_key = create([&witness](key_object& k) { k.key_data = witness.block_signing_key; }); + const key_object& signing_key = create([&witness](key_object& k) { + k.key_data = witness.block_signing_key; + }); witness_create_operation op; op.block_signing_key = signing_key.get_id(); op.initial_secret = witness.initial_secret; - op.witness_account = witness_account.get_id(); - witness_id_type id = apply_operation(genesis_eval_state, op).get(); - init_witnesses.emplace(id); + op.witness_account = get_account_id(witness.owner_name); + apply_operation(genesis_eval_state, op).get(); }); - std::for_each(genesis_state.initial_committee.begin(), genesis_state.initial_committee.end(), + std::for_each(genesis_state.initial_committee_candidates.begin(), genesis_state.initial_committee_candidates.end(), [&](const genesis_state_type::initial_committee_member_type& member) { - const account_object& member_account = *accounts_by_name.find(member.owner_name); delegate_create_operation op; - op.delegate_account = member_account.get_id(); - delegate_id_type id = apply_operation(genesis_eval_state, op).get(); - init_delegates.emplace(id); + op.delegate_account = get_account_id(member.owner_name); + apply_operation(genesis_eval_state, op).get(); }); - // Set initial witnesses and committee as active + // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { - p.active_delegates = vector(init_delegates.begin(), init_delegates.end()); - p.active_witnesses = init_witnesses; - std::transform(p.active_witnesses.begin(), p.active_witnesses.end(), - std::inserter(p.witness_accounts, p.witness_accounts.begin()), - [&](witness_id_type id) { return get(id).witness_account; }); + auto idx = get_index_type().indices(); + for( auto itr = idx.begin(); + itr != idx.end() && p.active_witnesses.size() < genesis_state.initial_active_witnesses; + ++itr ) + { + p.active_witnesses.insert(itr->id); + p.witness_accounts.insert(itr->witness_account); + } }); // Initialize witness schedule @@ -383,6 +467,8 @@ void database::init_genesis(const genesis_state_type& genesis_state) witness_scheduler_rng rng(_wso.rng_seed.begin(), GRAPHENE_NEAR_SCHEDULE_CTR_IV); + auto init_witnesses = get_global_properties().active_witnesses; + _wso.scheduler = witness_scheduler(); _wso.scheduler._min_token_count = init_witnesses.size() / 2; _wso.scheduler.update(init_witnesses); @@ -391,7 +477,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) _wso.scheduler.produce_schedule(rng); _wso.last_scheduling_block = 0; - }) ; + }); assert( wso.id == witness_schedule_id_type() ); // Enable fees diff --git a/libraries/chain/db_witness_schedule.cpp b/libraries/chain/db_witness_schedule.cpp index 92e75afb..5095ac1b 100644 --- a/libraries/chain/db_witness_schedule.cpp +++ b/libraries/chain/db_witness_schedule.cpp @@ -118,7 +118,7 @@ void database::update_witness_schedule(signed_block next_block) _wso.slots_since_genesis += schedule_slot; witness_scheduler_rng rng(wso.rng_seed.data, _wso.slots_since_genesis); - _wso.scheduler._min_token_count = gpo.active_witnesses.size() / 2; + _wso.scheduler._min_token_count = std::max(int(gpo.active_witnesses.size()) / 2, 1); uint32_t drain = schedule_slot; while( drain > 0 ) { diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index a3781143..955b88b6 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -110,11 +110,11 @@ namespace graphene { namespace chain { { FC_ASSERT(amount.asset_id == id); return amount_to_pretty_string(amount.amount); } /// Ticker symbol for this asset, i.e. "USD" - string symbol; + string symbol; /// Maximum number of digits after the decimal point (must be <= 12) - uint8_t precision; + uint8_t precision; /// ID of the account which issued this asset. - account_id_type issuer; + account_id_type issuer; /** * @brief The asset_options struct contains options available on all assets in the network @@ -124,17 +124,18 @@ namespace graphene { namespace chain { struct asset_options { /// The maximum supply of this asset which may exist at any given time. This can be as large as /// GRAPHENE_MAX_SHARE_SUPPLY - share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY; + share_type max_supply = GRAPHENE_MAX_SHARE_SUPPLY; /// When this asset is traded on the markets, this percentage of the total traded will be exacted and paid /// to the issuer. This is a fixed point value, representing hundredths of a percent, i.e. a value of 100 /// in this field means a 1% fee is charged on market trades of this asset. - uint16_t market_fee_percent = 0; - share_type max_market_fee = GRAPHENE_MAX_SHARE_SUPPLY; + uint16_t market_fee_percent = 0; + /// Market fees calculated as @ref market_fee_percent of the traded volume are capped to this value + share_type max_market_fee = GRAPHENE_MAX_SHARE_SUPPLY; /// The flags which the issuer has permission to update. See @ref asset_issuer_permission_flags - uint16_t issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; + uint16_t issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK; /// The currently active flags on this permission. See @ref asset_issuer_permission_flags - uint16_t flags = 0; + uint16_t flags = 0; /// When a non-core asset is used to pay a fee, the blockchain must convert that asset to core asset in /// order to accept the fee. If this asset's fee pool is funded, the chain will automatically deposite fees @@ -161,7 +162,7 @@ namespace graphene { namespace chain { * data that describes the meaning/purpose of this asset, fee will be charged proportional to * size of description. */ - string description; + string description; /// Perform internal consistency checks. /// @throws fc::exception if any check fails @@ -197,7 +198,7 @@ namespace graphene { namespace chain { }; /// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently. - dynamic_asset_data_id_type dynamic_asset_data_id; + asset_dynamic_data_id_type dynamic_asset_data_id; /// Extra data associated with BitAssets. This field is non-null if and only if is_market_issued() returns true optional bitasset_data_id; @@ -263,17 +264,18 @@ namespace graphene { namespace chain { share_type max_force_settlement_volume(share_type current_supply)const; /** return true if there has been a black swan, false otherwise */ - bool has_settlement()const { return !settlement_price.is_null(); } + bool has_settlement()const { return !settlement_price.is_null(); } /** - * In the event of a black swan, the swan price is saved in the settlement price, - * and all margin positions are settled at the same price with the siezed collateral - * being moved into the settlement fund. From this point on no further updates to - * the asset are permitted (no feeds, etc) and forced settlement occurs using - * the settlement price and fund. + * In the event of a black swan, the swan price is saved in the settlement price, and all margin positions + * are settled at the same price with the siezed collateral being moved into the settlement fund. From this + * point on no further updates to the asset are permitted (no feeds, etc) and forced settlement occurs + * immediately when requested, using the settlement price and fund. */ ///@{ - price settlement_price; + /// Price at which force settlements of a black swanned asset will occur + price settlement_price; + /// Amount of collateral which is available for force settlement share_type settlement_fund; ///@} diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 6f0cb194..1f00bb19 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -39,54 +40,6 @@ namespace graphene { namespace chain { using graphene::db::abstract_object; using graphene::db::object; - struct genesis_state_type { - struct initial_account_type { - initial_account_type(const string& name = string(), - const public_key_type& owner_key = public_key_type(), - const public_key_type& active_key = public_key_type(), - bool is_lifetime_member = false) - : name(name), - owner_key(owner_key), - active_key(active_key == public_key_type()? owner_key : active_key), - is_lifetime_member(is_lifetime_member) - {} - string name; - public_key_type owner_key; - public_key_type active_key; - bool is_lifetime_member; - }; - struct initial_balance_type { - address owner; - string asset_symbol; - share_type amount; - }; - struct initial_vesting_balance_type { - address owner; - string asset_symbol; - share_type amount; - time_point_sec vesting_start_date; - time_point_sec earliest_withdrawal_date; - time_point_sec vesting_end_date; - }; - struct initial_witness_type { - /// Must correspond to one of the allocation targets. - string owner_name; - public_key_type block_signing_key; - secret_hash_type initial_secret; - }; - struct initial_committee_member_type { - /// Must correspond to one of the allocation targets. - string owner_name; - }; - - chain_parameters initial_parameters; - vector initial_accounts; - vector initial_balances; - vector initial_vesting_balances; - vector initial_witnesses; - vector initial_committee; - }; - namespace detail { /** @@ -527,14 +480,3 @@ namespace graphene { namespace chain { } } } } - -FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, - (owner)(asset_symbol)(amount)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, - (owner)(asset_symbol)(amount)(vesting_start_date)(earliest_withdrawal_date)(vesting_end_date)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)(initial_secret)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) -FC_REFLECT(graphene::chain::genesis_state_type, - (initial_parameters)(initial_accounts)(initial_balances) - (initial_vesting_balances)(initial_witnesses)(initial_committee)) diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index 7e2fb9f0..7be0a5df 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -197,7 +197,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; - typedef object_id< implementation_ids, impl_asset_dynamic_data_type, asset_dynamic_data_object> dynamic_asset_data_id_type; + typedef object_id< implementation_ids, impl_asset_dynamic_data_type, asset_dynamic_data_object> asset_dynamic_data_id_type; typedef object_id< implementation_ids, impl_asset_bitasset_data_type, asset_bitasset_data_object> asset_bitasset_data_id_type; typedef object_id< implementation_ids, impl_account_balance_object_type, account_balance_object> account_balance_id_type; typedef object_id< implementation_ids, impl_account_statistics_object_type,account_statistics_object> account_statistics_id_type; @@ -646,7 +646,7 @@ FC_REFLECT_TYPENAME( graphene::chain::relative_key_id_type ) FC_REFLECT_TYPENAME( graphene::chain::relative_account_id_type ) FC_REFLECT_TYPENAME( graphene::chain::global_property_id_type ) FC_REFLECT_TYPENAME( graphene::chain::dynamic_global_property_id_type ) -FC_REFLECT_TYPENAME( graphene::chain::dynamic_asset_data_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::asset_dynamic_data_id_type ) FC_REFLECT_TYPENAME( graphene::chain::asset_bitasset_data_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_balance_id_type ) FC_REFLECT_TYPENAME( graphene::chain::account_statistics_id_type ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 65e45856..b26c12b3 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -70,8 +70,8 @@ database_fixture::database_fixture() delegate_priv_key.get_public_key(), delegate_priv_key.get_public_key(), true); - genesis_state.initial_committee.push_back({name}); - genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret}); + genesis_state.initial_committee_candidates.push_back({name}); + genesis_state.initial_witness_candidates.push_back({name, delegate_priv_key.get_public_key(), secret}); } fc::reflector::visit(fee_schedule_type::fee_set_visitor{genesis_state.initial_parameters.current_fees, 0}); db.init_genesis(genesis_state); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 037b8c4d..5afbd573 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -49,8 +49,8 @@ genesis_state_type make_genesis() { delegate_priv_key.get_public_key(), delegate_priv_key.get_public_key(), true); - genesis_state.initial_committee.push_back({name}); - genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret}); + genesis_state.initial_committee_candidates.push_back({name}); + genesis_state.initial_witness_candidates.push_back({name, delegate_priv_key.get_public_key(), secret}); } fc::reflector::visit(fee_schedule_type::fee_set_visitor{genesis_state.initial_parameters.current_fees, 0}); return genesis_state;