/* * 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 #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(); 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(); // this is the fast effecient version for validation only // add_index< primary_index> >(); // this is the slower version designed to aid GUI use. We will // default to the "slow" version until we need a faster version. add_index< primary_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 >(); //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_witnesses.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( [&null_private_key](key_object& k) { k.key_data = public_key_type(null_private_key.get_public_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 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() ) { for( const auto& account : genesis_state.initial_accounts ) { key_id_type key_id = apply_operation(genesis_eval_state, key_create_operation({asset(), committee_account.id, account.owner_key})).get(); account_create_operation cop; cop.name = account.name; cop.registrar = account_id_type(1); 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, account.owner_key})).get(); cop.active = authority(1, key_id, 1); } else { cop.active = cop.owner; } cop.options.memo_key = key_id; 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); } } } // 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,{})); } 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(), [&](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; }); 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); }); std::for_each(genesis_state.initial_committee.begin(), genesis_state.initial_committee.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); }); // Set initial witnesses and committee as active 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; }); }); // 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); _wso.scheduler = witness_scheduler(); _wso.scheduler._min_token_count = init_witnesses.size() / 2; _wso.scheduler.update(init_witnesses); for( size_t i=0; i