/* * Copyright (c) 2015, Cryptonomex, Inc. * All rights reserved. * * This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and * the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification, * are permitted until September 8, 2015, provided that the following conditions are met: * * 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace graphene { namespace chain { void database::initialize_evaluators() { _operation_evaluators.resize(255); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); register_evaluator(); } void database::initialize_indexes() { reset_indexes(); //Protocol object indexes add_index< primary_index >(); add_index< primary_index >(); auto acnt_index = add_index< primary_index >(); acnt_index->add_secondary_index(); acnt_index->add_secondary_index(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); auto prop_index = add_index< primary_index >(); prop_index->add_secondary_index(); add_index< primary_index >(); //add_index< primary_index >(); add_index< primary_index> >(); add_index< primary_index >(); add_index< primary_index >(); //Implementation object indexes add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index> >(); add_index< primary_index> >(); add_index< primary_index> >(); add_index< primary_index> >(); add_index< primary_index> >(); add_index< primary_index> >(); } void database::init_genesis(const genesis_state_type& genesis_state) { try { FC_ASSERT(genesis_state.initial_witness_candidates.size() > 0, "Cannot start a chain with zero witnesses."); _undo_db.disable(); struct auth_inhibitor { auth_inhibitor(database& db) : db(db), old_flags(db.node_properties().skip_flags) { db.node_properties().skip_flags |= skip_authority_check; } ~auth_inhibitor() { db.node_properties().skip_flags = old_flags; } private: database& db; uint32_t old_flags; } inhibitor(*this); transaction_evaluation_state genesis_eval_state(this); // Create blockchain accounts fc::ecc::private_key null_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key"))); create([](account_balance_object& b) { b.balance = GRAPHENE_MAX_SHARE_SUPPLY; }); const account_object& committee_account = create( [&](account_object& n) { n.membership_expiration_date = time_point_sec::maximum(); n.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; n.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; n.owner.weight_threshold = 1; n.active.weight_threshold = 1; n.name = "committee-account"; n.statistics = create( [&](account_statistics_object& b){}).id; }); FC_ASSERT(committee_account.get_id() == GRAPHENE_COMMITTEE_ACCOUNT); FC_ASSERT(create([this](account_object& a) { a.name = "witness-account"; a.statistics = create([](account_statistics_object&){}).id; a.owner.weight_threshold = 1; a.active.weight_threshold = 1; a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_WITNESS_ACCOUNT; a.membership_expiration_date = time_point_sec::maximum(); a.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; }).get_id() == GRAPHENE_WITNESS_ACCOUNT); FC_ASSERT(create([this](account_object& a) { a.name = "relaxed-committee-account"; a.statistics = create([](account_statistics_object&){}).id; a.owner.weight_threshold = 1; a.active.weight_threshold = 1; a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT; a.membership_expiration_date = time_point_sec::maximum(); a.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; }).get_id() == GRAPHENE_RELAXED_COMMITTEE_ACCOUNT); FC_ASSERT(create([this](account_object& a) { a.name = "null-account"; a.statistics = create([](account_statistics_object&){}).id; a.owner.weight_threshold = 1; a.active.weight_threshold = 1; a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_NULL_ACCOUNT; a.membership_expiration_date = time_point_sec::maximum(); a.network_fee_percentage = 0; a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT; }).get_id() == GRAPHENE_NULL_ACCOUNT); FC_ASSERT(create([this](account_object& a) { a.name = "temp-account"; a.statistics = create([](account_statistics_object&){}).id; a.owner.weight_threshold = 0; a.active.weight_threshold = 0; a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_TEMP_ACCOUNT; a.membership_expiration_date = time_point_sec::maximum(); a.network_fee_percentage = GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT - GRAPHENE_DEFAULT_NETWORK_PERCENT_OF_FEE; }).get_id() == GRAPHENE_TEMP_ACCOUNT); // Create core asset const asset_dynamic_data_object& dyn_asset = create([&](asset_dynamic_data_object& a) { a.current_supply = GRAPHENE_MAX_SHARE_SUPPLY; }); const asset_object& core_asset = create( [&]( asset_object& a ) { a.symbol = GRAPHENE_SYMBOL; a.options.max_supply = GRAPHENE_MAX_SHARE_SUPPLY; a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; a.options.flags = 0; a.options.issuer_permissions = 0; a.issuer = committee_account.id; a.options.core_exchange_rate.base.amount = 1; a.options.core_exchange_rate.base.asset_id = 0; a.options.core_exchange_rate.quote.amount = 1; a.options.core_exchange_rate.quote.asset_id = 0; a.dynamic_asset_data_id = dyn_asset.id; }); assert( asset_id_type(core_asset.id) == asset().asset_id ); assert( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); (void)core_asset; // Create global properties create([&](global_property_object& p) { p.chain_id = fc::digest(genesis_state); p.parameters = genesis_state.initial_parameters; // Set fees to zero initially, so that genesis initialization needs not pay them // We'll fix it at the end of the function fc::reflector::visit(fee_schedule_type::fee_set_visitor{p.parameters.current_fees, 0}); }); create( [&](dynamic_global_property_object& p) { p.time = fc::time_point_sec(GRAPHENE_GENESIS_TIMESTAMP); p.witness_budget = 0; }); create([&](block_summary_object&) {}); // Create initial accounts for( const auto& account : genesis_state.initial_accounts ) { /* key_id_type key_id = apply_operation(genesis_eval_state, key_create_operation({asset(), GRAPHENE_TEMP_ACCOUNT, account.owner_key})).get(); */ account_create_operation cop; cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); if( account.owner_key != account.active_key ) { /* key_id = apply_operation(genesis_eval_state, key_create_operation({asset(), GRAPHENE_TEMP_ACCOUNT, account.owner_key})).get(); */ cop.active = authority(1, account.owner_key, 1); } else { cop.active = cop.owner; } cop.options.memo_key = account.owner_key; account_id_type account_id(apply_operation(genesis_eval_state, cop).get()); if( account.is_lifetime_member ) { account_upgrade_operation op; op.account_to_upgrade = account_id; op.upgrade_to_lifetime_member = true; apply_operation(genesis_eval_state, op); } } 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(); }; 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, collateral_rec.owner, 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; 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 for( const genesis_state_type::initial_vesting_balance_type& vest : genesis_state.initial_vesting_balances ) { create([&](balance_object& b) { b.owner = vest.owner; b.balance = asset(vest.amount, assets_by_symbol.find(vest.asset_symbol)->get_id()); linear_vesting_policy policy; policy.begin_timestamp = vest.begin_timestamp; policy.vesting_cliff_seconds = 0; policy.vesting_duration_seconds = vest.vesting_duration_seconds; policy.begin_balance = vest.begin_balance; b.vesting_policy = std::move(policy); }); total_allocation += vest.amount; } // Set current supply based on allocations, if they happened if( total_allocation > 0 ) { modify(dyn_asset, [total_allocation](asset_dynamic_data_object& d) { d.current_supply = total_allocation; }); adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{})); } // Create initial witnesses and delegates std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { /* 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 = witness.block_signing_key; op.initial_secret = witness.initial_secret; op.witness_account = get_account_id(witness.owner_name); apply_operation(genesis_eval_state, op).get(); }); std::for_each(genesis_state.initial_committee_candidates.begin(), genesis_state.initial_committee_candidates.end(), [&](const genesis_state_type::initial_committee_member_type& member) { delegate_create_operation op; op.delegate_account = get_account_id(member.owner_name); apply_operation(genesis_eval_state, op).get(); }); // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { 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 #ifndef NDEBUG const witness_schedule_object& wso = #endif create([&](witness_schedule_object& _wso) { memset(_wso.rng_seed.begin(), 0, _wso.rng_seed.size()); 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); for( size_t i=0; i