From 66c9606652f8edc571033a5e4a7a3bbbd146ef61 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 1 Jul 2015 17:18:49 -0400 Subject: [PATCH 1/3] 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; From e9b015b7689a901c9f72cc217099957c0c739b56 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Wed, 1 Jul 2015 17:25:06 -0400 Subject: [PATCH 2/3] Add missing header. Derp --- .../include/graphene/chain/genesis_state.hpp | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 libraries/chain/include/graphene/chain/genesis_state.hpp diff --git a/libraries/chain/include/graphene/chain/genesis_state.hpp b/libraries/chain/include/graphene/chain/genesis_state.hpp new file mode 100644 index 00000000..d193d5f6 --- /dev/null +++ b/libraries/chain/include/graphene/chain/genesis_state.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include + +#include +#include + +namespace graphene { namespace chain { +using std::string; +using std::vector; + +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_asset_type { + string symbol; + string description; + uint8_t precision; + string issuer_name; + share_type max_supply; + uint16_t market_fee_percent; + share_type max_market_fee; + uint16_t issuer_permissions; + uint16_t flags; + + struct initial_bitasset_options { + uint32_t feed_lifetime_sec; + uint8_t minimum_feeds; + uint32_t force_settlement_delay_sec; + uint16_t force_settlement_offset_percent; + uint16_t maximum_force_settlement_volume; + string backing_asset_symbol; + + struct initial_collateral_position { + address owner; + share_type collateral; + share_type debt; + }; + + uint16_t maintenance_collateral_ratio; + vector collateral_records; + }; + optional bitasset_options; + + share_type initial_accumulated_fees; + }; + 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 initial accounts + 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 initial accounts + string owner_name; + }; + + chain_parameters initial_parameters; + vector initial_accounts; + vector initial_assets; + vector initial_balances; + vector initial_vesting_balances; + int initial_active_witnesses = GRAPHENE_DEFAULT_NUM_WITNESSES; + vector initial_witness_candidates; + // These are only candidates; the chain will have no active committee members at genesis + vector initial_committee_candidates; +}; +} } // namespace graphene::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_asset_type::initial_bitasset_options::initial_collateral_position, + (collateral)(debt)) +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_bitasset_options, + (feed_lifetime_sec)(minimum_feeds)(force_settlement_delay_sec)(force_settlement_offset_percent) + (maximum_force_settlement_volume)(backing_asset_symbol)(maintenance_collateral_ratio)(collateral_records)) +FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type, + (symbol)(description)(precision)(issuer_name)(max_supply)(market_fee_percent) + (issuer_permissions)(flags)(bitasset_options)(initial_accumulated_fees)) + +FC_REFLECT(graphene::chain::genesis_state_type, + (initial_parameters)(initial_accounts)(initial_assets)(initial_balances) + (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) + (initial_committee_candidates)) From acd595f889f94fa8201ad3eb4b9f309554c0495a Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Wed, 1 Jul 2015 17:47:16 -0400 Subject: [PATCH 3/3] Add missing functions for registering delegates --- libraries/app/api.cpp | 35 +++++++++++++ libraries/app/include/graphene/app/api.hpp | 19 +++++++ .../wallet/include/graphene/wallet/wallet.hpp | 26 +++++++++- libraries/wallet/wallet.cpp | 49 +++++++++++++++++-- 4 files changed, 125 insertions(+), 4 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 1360303e..283e3a80 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -302,6 +302,29 @@ namespace graphene { namespace app { return witnesses_by_account_name; } + map database_api::lookup_delegate_accounts(const string& lower_bound_name, uint32_t limit)const + { + FC_ASSERT( limit <= 1000 ); + const auto& delegates_by_id = _db.get_index_type().indices().get(); + + // we want to order delegates by account name, but that name is in the account object + // so the delegate_index doesn't have a quick way to access it. + // get all the names and look them all up, sort them, then figure out what + // records to return. This could be optimized, but we expect the + // number of delegates to be few and the frequency of calls to be rare + std::map delegates_by_account_name; + for (const delegate_object& delegate : delegates_by_id) + if (auto account_iter = _db.find(delegate.delegate_account)) + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + delegates_by_account_name.insert(std::make_pair(account_iter->name, delegate.id)); + + auto end_iter = delegates_by_account_name.begin(); + while (end_iter != delegates_by_account_name.end() && limit--) + ++end_iter; + delegates_by_account_name.erase(end_iter, delegates_by_account_name.end()); + return delegates_by_account_name; + } + vector> database_api::get_witnesses(const vector& witness_ids)const { vector> result; result.reserve(witness_ids.size()); @@ -314,6 +337,18 @@ namespace graphene { namespace app { return result; } + vector> database_api::get_delegates(const vector& delegate_ids)const + { + vector> result; result.reserve(delegate_ids.size()); + std::transform(delegate_ids.begin(), delegate_ids.end(), std::back_inserter(result), + [this](delegate_id_type id) -> optional { + if(auto o = _db.find(id)) + return *o; + return {}; + }); + return result; + } + login_api::login_api(application& a) :_app(a) { diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index c9fff614..7a69cd8f 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -206,6 +206,14 @@ namespace graphene { namespace app { */ map lookup_witness_accounts(const string& lower_bound_name, uint32_t limit)const; + /** + * @brief Get names and IDs for registered delegates + * @param lower_bound_name Lower bound of the first name to return + * @param limit Maximum number of results to return -- must not exceed 1000 + * @return Map of delegate names to corresponding IDs + */ + map lookup_delegate_accounts(const string& lower_bound_name, uint32_t limit)const; + /** * @brief Get a list of witnesses by ID * @param witness_ids IDs of the witnesses to retrieve @@ -215,6 +223,15 @@ namespace graphene { namespace app { */ vector> get_witnesses(const vector& witness_ids)const; + /** + * @brief Get a list of delegates by ID + * @param delegate_ids IDs of the delegates to retrieve + * @return The delegates corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_delegates(const vector& delegate_ids)const; + /** * @group Push Notification Methods * These methods may be used to get push notifications whenever an object or market is changed @@ -441,9 +458,11 @@ FC_API(graphene::app::database_api, (list_assets) (get_delegate_by_account) (get_witnesses) + (get_delegates) (get_witness_by_account) (get_witness_count) (lookup_witness_accounts) + (lookup_delegate_accounts) (subscribe_to_objects) (unsubscribe_from_objects) (subscribe_to_market) diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index f7180f59..8e88889a 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -807,10 +807,13 @@ class wallet_api * An account can have at most one delegate object. * * @param owner_account the name or id of the account which is creating the delegate + * @param url a URL to include in the delegate record in the blockchain. Clients may + * display this when showing a list of delegates. May be blank. * @param broadcast true to broadcast the transaction on the network * @returns the signed transaction registering a delegate */ signed_transaction create_delegate(string owner_account, + string url, bool broadcast = false); /** Lists all witnesses registered in the blockchain. @@ -828,12 +831,33 @@ class wallet_api */ map list_witnesses(const string& lowerbound, uint32_t limit); + /** Lists all delegates registered in the blockchain. + * This returns a list of all account names that own delegates, and the associated delegate id, + * sorted by name. This lists delegates whether they are currently voted in or not. + * + * Use the \c lowerbound and limit parameters to page through the list. To retrieve all delegates, + * start by setting \c lowerbound to the empty string \c "", and then each iteration, pass + * the last delegate name returned as the \c lowerbound for the next \c list_delegates() call. + * + * @param lowerbound the name of the first delegate to return. If the named delegate does not exist, + * the list will start at the delegate that comes after \c lowerbound + * @param limit the maximum number of delegates to return (max: 1000) + * @returns a list of delegates mapping delegate names to delegate ids + */ + map list_delegates(const string& lowerbound, uint32_t limit); + /** Returns information about the given witness. - * @param witness_name_or_id the name or id of the witness account owner, or the id of the witness + * @param owner_account the name or id of the witness account owner, or the id of the witness * @returns the information about the witness stored in the block chain */ witness_object get_witness(string owner_account); + /** Returns information about the given delegate. + * @param owner_account the name or id of the delegate account owner, or the id of the delegate + * @returns the information about the delegate stored in the block chain + */ + delegate_object get_delegate(string owner_account); + /** Creates a witness object owned by the given account. * * An account can have at most one witness object. diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 5701bc8a..c22d9414 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -279,12 +279,14 @@ private: } } } + void enable_umask_protection() { #ifdef __unix__ _old_umask = umask( S_IRWXG | S_IRWXO ); #endif } + void disable_umask_protection() { #ifdef __unix__ @@ -1169,12 +1171,13 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (authorizing_account)(account_to_list)(new_listing_status)(broadcast) ) } - signed_transaction create_delegate(string owner_account, + signed_transaction create_delegate(string owner_account, string url, bool broadcast /* = false */) { try { delegate_create_operation delegate_create_op; delegate_create_op.delegate_account = get_account_id(owner_account); + delegate_create_op.url = url; if (_remote_db->get_delegate_by_account(delegate_create_op.delegate_account)) FC_THROW("Account ${owner_account} is already a delegate", ("owner_account", owner_account)); @@ -1221,6 +1224,41 @@ public: FC_CAPTURE_AND_RETHROW( (owner_account) ) } + delegate_object get_delegate(string owner_account) + { + try + { + fc::optional delegate_id = maybe_id(owner_account); + if (delegate_id) + { + std::vector ids_to_get; + ids_to_get.push_back(*delegate_id); + std::vector> delegate_objects = _remote_db->get_delegates(ids_to_get); + if (delegate_objects.front()) + return *delegate_objects.front(); + FC_THROW("No delegate is registered for id ${id}", ("id", owner_account)); + } + else + { + // then maybe it's the owner account + try + { + account_id_type owner_account_id = get_account_id(owner_account); + fc::optional delegate = _remote_db->get_delegate_by_account(owner_account_id); + if (delegate) + return *delegate; + else + FC_THROW("No delegate is registered for account ${account}", ("account", owner_account)); + } + catch (const fc::exception&) + { + FC_THROW("No account or delegate named ${account}", ("account", owner_account)); + } + } + } + FC_CAPTURE_AND_RETHROW( (owner_account) ) + } + signed_transaction create_witness(string owner_account, string url, bool broadcast /* = false */) @@ -2072,10 +2110,10 @@ signed_transaction wallet_api::whitelist_account(string authorizing_account, return my->whitelist_account(authorizing_account, account_to_list, new_listing_status, broadcast); } -signed_transaction wallet_api::create_delegate(string owner_account, +signed_transaction wallet_api::create_delegate(string owner_account, string url, bool broadcast /* = false */) { - return my->create_delegate(owner_account, broadcast); + return my->create_delegate(owner_account, url, broadcast); } map wallet_api::list_witnesses(const string& lowerbound, uint32_t limit) @@ -2083,6 +2121,11 @@ map wallet_api::list_witnesses(const string& lowerbound, return my->_remote_db->lookup_witness_accounts(lowerbound, limit); } +map wallet_api::list_delegates(const string& lowerbound, uint32_t limit) +{ + return my->_remote_db->lookup_delegate_accounts(lowerbound, limit); +} + witness_object wallet_api::get_witness(string owner_account) { return my->get_witness(owner_account);