/** * This method dumps the state of the blockchain in a semi-human readable form for the * purpose of tracking down funds and mismatches in currency allocation */ void database::debug_dump() { const auto& db = *this; const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db); const auto& balance_index = db.get_index_type<account_balance_index>().indices(); const simple_index<account_statistics_object>& statistics_index = db.get_index_type<simple_index<account_statistics_object>>(); map<asset_id_type,share_type> total_balances; map<asset_id_type,share_type> total_debts; share_type core_in_orders; share_type reported_core_in_orders; for( const account_balance_object& a : balance_index ) { // idump(("balance")(a)); total_balances[a.asset_type] += a.balance; } for( const account_statistics_object& s : statistics_index ) { // idump(("statistics")(s)); reported_core_in_orders += s.total_core_in_orders; } for( const limit_order_object& o : db.get_index_type<limit_order_index>().indices() ) { // idump(("limit_order")(o)); auto for_sale = o.amount_for_sale(); if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount; total_balances[for_sale.asset_id] += for_sale.amount; } for( const call_order_object& o : db.get_index_type<call_order_index>().indices() ) { // idump(("call_order")(o)); auto col = o.get_collateral(); if( col.asset_id == asset_id_type() ) core_in_orders += col.amount; total_balances[col.asset_id] += col.amount; total_debts[o.get_debt().asset_id] += o.get_debt().amount; } for( const asset_object& asset_obj : db.get_index_type<asset_index>().indices() ) { total_balances[asset_obj.id] += asset_obj.dynamic_asset_data_id(db).accumulated_fees; total_balances[asset_id_type()] += asset_obj.dynamic_asset_data_id(db).fee_pool; // edump((total_balances[asset_obj.id])(asset_obj.dynamic_asset_data_id(db).current_supply ) ); } if( total_balances[asset_id_type()].value != core_asset_data.current_supply.value ) { edump( (total_balances[asset_id_type()].value)(core_asset_data.current_supply.value )); } edump((core_in_orders)(reported_core_in_orders)); /* const auto& vbidx = db.get_index_type<simple_index<vesting_balance_object>>(); for( const auto& s : vbidx ) { // idump(("vesting_balance")(s)); } */ }
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives ) { try { //idump((pays)(receives)(order)); FC_ASSERT( order.get_debt().asset_id == receives.asset_id ); FC_ASSERT( order.get_collateral().asset_id == pays.asset_id ); FC_ASSERT( order.get_collateral() >= pays ); optional<asset> collateral_freed; modify( order, [&]( call_order_object& o ){ o.debt -= receives.amount; o.collateral -= pays.amount; if( o.debt == 0 ) { collateral_freed = o.get_collateral(); o.collateral = 0; } }); const asset_object& mia = receives.asset_id(*this); assert( mia.is_market_issued() ); const asset_dynamic_data_object& mia_ddo = mia.dynamic_asset_data_id(*this); modify( mia_ddo, [&]( asset_dynamic_data_object& ao ){ //idump((receives)); ao.current_supply -= receives.amount; }); const account_object& borrower = order.borrower(*this); if( collateral_freed || pays.asset_id == asset_id_type() ) { const account_statistics_object& borrower_statistics = borrower.statistics(*this); if( collateral_freed ) adjust_balance(borrower.get_id(), *collateral_freed); modify( borrower_statistics, [&]( account_statistics_object& b ){ if( collateral_freed && collateral_freed->amount > 0 ) b.total_core_in_orders -= collateral_freed->amount; if( pays.asset_id == asset_id_type() ) b.total_core_in_orders -= pays.amount; assert( b.total_core_in_orders >= 0 ); }); } assert( pays.asset_id != receives.asset_id ); push_applied_operation( fill_order_operation{ order.id, order.borrower, pays, receives, asset(0, pays.asset_id) } ); if( collateral_freed ) remove( order ); return collateral_freed.valid(); } FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
void refund_worker_type::pay_worker(share_type pay, database& db) { total_burned += pay; db.modify(db.get(asset_id_type()).dynamic_data(db), [pay](asset_dynamic_data_object& d) { d.current_supply -= pay; }); }
void standard_asset() { set_expiration( db, trx ); const auto& bitusd = create_bitasset("USDBIT", _feedproducer); _swan = bitusd.id; _back = asset_id_type(); update_feed_producers(swan(), {_feedproducer}); }
void database::pay_order( const account_object& receiver, const asset& receives, const asset& pays ) { const auto& balances = receiver.statistics(*this); modify( balances, [&]( account_statistics_object& b ){ if( pays.asset_id == asset_id_type() ) b.total_core_in_orders -= pays.amount; }); adjust_balance(receiver.get_id(), receives); }
void transaction_evaluation_state::update_delegate_votes() { auto asset_rec = _current_state->get_asset_record( asset_id_type() ); for( const auto& del_vote : net_delegate_votes ) { auto del_rec = _current_state->get_account_record( del_vote.first ); FC_ASSERT( !!del_rec ); del_rec->adjust_votes_for( del_vote.second.votes_for ); _current_state->store_account_record( *del_rec ); } }
/** * Process all fees and update the asset records. */ void transaction_evaluation_state::post_evaluate() { try { for( const auto& item : withdraws ) { auto asset_rec = _current_state->get_asset_record( item.first ); if( !asset_rec.valid() ) FC_CAPTURE_AND_THROW( unknown_asset_id, (item) ); if( asset_rec->id > 0 && asset_rec->is_market_issued() && asset_rec->transaction_fee > 0 ) { sub_balance( address(), asset(asset_rec->transaction_fee, asset_rec->id) ); } } balance[0]; // make sure we have something for this. for( const auto& fee : balance ) { if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) ); // if the fee is already in XTS or the fee balance is zero, move along... if( fee.first == 0 || fee.second == 0 ) continue; auto asset_record = _current_state->get_asset_record( fee.first ); if( !asset_record.valid() ) FC_CAPTURE_AND_THROW( unknown_asset_id, (fee.first) ); if( !asset_record->is_market_issued() ) continue; // lowest ask is someone with XTS offered at a price of USD / XTS, fee.first // is an amount of USD which can be converted to price*USD XTS provided we // send lowest_ask.index.owner the USD oprice median_price = _current_state->get_median_delegate_price( fee.first, asset_id_type( 0 ) ); if( median_price ) { // fees paid in something other than XTS are discounted 50% alt_fees_paid += asset( (fee.second*2)/3, fee.first ) * *median_price; } } for( const auto& fee : balance ) { if( fee.second < 0 ) FC_CAPTURE_AND_THROW( negative_fee, (fee) ); if( fee.second > 0 ) // if a fee was paid... { auto asset_record = _current_state->get_asset_record( fee.first ); if( !asset_record ) FC_CAPTURE_AND_THROW( unknown_asset_id, (fee.first) ); asset_record->collected_fees += fee.second; _current_state->store_asset_record( *asset_record ); } } } FC_RETHROW_EXCEPTIONS( warn, "" ) }
asset fee_schedule::calculate_fee( const operation& op, const price& core_exchange_rate )const { auto base_value = op.visit( calc_fee_visitor( *this, op ) ); auto scaled = fc::uint128(base_value) * scale; scaled /= GRAPHENE_100_PERCENT; FC_ASSERT( scaled <= GRAPHENE_MAX_SHARE_SUPPLY ); //idump( (base_value)(scaled)(core_exchange_rate) ); auto result = asset( scaled.to_uint64(), asset_id_type(0) ) * core_exchange_rate; //FC_ASSERT( result * core_exchange_rate >= asset( scaled.to_uint64()) ); while( result * core_exchange_rate < asset( scaled.to_uint64()) ) result.amount++; FC_ASSERT( result.amount <= GRAPHENE_MAX_SHARE_SUPPLY ); return result; }
vector<balance_object> database_api::get_balance_objects( const vector<address>& addrs )const { try { const auto& bal_idx = _db.get_index_type<balance_index>(); const auto& by_owner_idx = bal_idx.indices().get<by_owner>(); vector<balance_object> result; for( const auto& owner : addrs ) { auto itr = by_owner_idx.lower_bound( boost::make_tuple( owner, asset_id_type(0) ) ); while( itr != by_owner_idx.end() && itr->owner == owner ) { result.push_back( *itr ); ++itr; } } return result; } FC_CAPTURE_AND_RETHROW( (addrs) ) }
asset fee_schedule::calculate_fee( const operation& op, const price& core_exchange_rate )const { //idump( (op)(core_exchange_rate) ); fee_parameters params; params.set_which(op.which()); auto itr = parameters.find(params); if( itr != parameters.end() ) params = *itr; auto base_value = op.visit( calc_fee_visitor( params ) ); auto scaled = fc::uint128(base_value) * scale; scaled /= GRAPHENE_100_PERCENT; FC_ASSERT( scaled <= GRAPHENE_MAX_SHARE_SUPPLY ); //idump( (base_value)(scaled)(core_exchange_rate) ); auto result = asset( scaled.to_uint64(), asset_id_type(0) ) * core_exchange_rate; //FC_ASSERT( result * core_exchange_rate >= asset( scaled.to_uint64()) ); while( result * core_exchange_rate < asset( scaled.to_uint64()) ) result.amount++; FC_ASSERT( result.amount <= GRAPHENE_MAX_SHARE_SUPPLY ); return result; }
void database::init_genesis(const genesis_allocation& initial_allocation) { try { _undo_db.disable(); fc::ecc::private_key genesis_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("genesis"))); const key_object& genesis_key = create<key_object>( [&genesis_private_key](key_object& k) { k.key_data = public_key_type(genesis_private_key.get_public_key()); }); const account_statistics_object& genesis_statistics = create<account_statistics_object>( [&](account_statistics_object& b){ }); create<account_balance_object>( [](account_balance_object& b) { b.balance = GRAPHENE_INITIAL_SUPPLY; }); const account_object& genesis_account = create<account_object>( [&](account_object& n) { n.name = "genesis"; n.owner.add_authority(genesis_key.get_id(), 1); n.owner.weight_threshold = 1; n.active = n.owner; n.memo_key = genesis_key.id; n.statistics = genesis_statistics.id; }); vector<delegate_id_type> init_delegates; vector<witness_id_type> init_witnesses; flat_set<witness_id_type> init_witness_set; auto delegates_and_witnesses = std::max(GRAPHENE_MIN_WITNESS_COUNT, GRAPHENE_MIN_DELEGATE_COUNT); for( int i = 0; i < delegates_and_witnesses; ++i ) { const account_statistics_object& stats_obj = create<account_statistics_object>( [&](account_statistics_object&){ }); const account_object& delegate_account = create<account_object>( [&](account_object& a) { a.active = a.owner = genesis_account.owner; a.name = string("init") + fc::to_string(i); a.statistics = stats_obj.id; }); const delegate_object& init_delegate = create<delegate_object>( [&](delegate_object& d) { d.delegate_account = delegate_account.id; d.vote_id = i * 2; }); init_delegates.push_back(init_delegate.id); const witness_object& init_witness = create<witness_object>( [&](witness_object& d) { d.witness_account = delegate_account.id; d.vote_id = i * 2 + 1; secret_hash_type::encoder enc; fc::raw::pack( enc, genesis_private_key ); fc::raw::pack( enc, d.last_secret ); d.next_secret = secret_hash_type::hash(enc.result()); }); init_witnesses.push_back(init_witness.id); init_witness_set.insert(init_witness.id); } create<block_summary_object>( [&](block_summary_object& p) { }); const witness_schedule_object& wso = create<witness_schedule_object>( [&]( 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_witness_set ); for( int i=0; i<init_witnesses.size(); i++ ) _wso.scheduler.produce_schedule( rng ); _wso.last_scheduling_block = 0; } ) ; assert( wso.id == witness_schedule_id_type() ); const global_property_object& properties = create<global_property_object>( [&](global_property_object& p) { p.active_delegates = init_delegates; for( const witness_id_type& wit : init_witnesses ) p.active_witnesses.insert( wit ); p.next_available_vote_id = delegates_and_witnesses * 2; p.chain_id = fc::digest(initial_allocation); }); (void)properties; create<dynamic_global_property_object>( [&](dynamic_global_property_object& p) { p.time = fc::time_point_sec( GRAPHENE_GENESIS_TIMESTAMP ); }); const asset_dynamic_data_object& dyn_asset = create<asset_dynamic_data_object>( [&]( asset_dynamic_data_object& a ) { a.current_supply = GRAPHENE_INITIAL_SUPPLY; }); const asset_object& core_asset = create<asset_object>( [&]( asset_object& a ) { a.symbol = GRAPHENE_SYMBOL; a.options.max_supply = GRAPHENE_INITIAL_SUPPLY; a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; a.options.flags = 0; a.options.issuer_permissions = 0; a.issuer = genesis_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; if( !initial_allocation.empty() ) { share_type total_allocation = 0; for( const auto& handout : initial_allocation ) total_allocation += handout.second; auto mangle_to_name = [](const fc::static_variant<public_key_type, address>& key) { string addr = string(key.which() == std::decay<decltype(key)>::type::tag<address>::value? key.get<address>() : key.get<public_key_type>()); string result = "bts"; string key_string = string(addr).substr(sizeof(GRAPHENE_ADDRESS_PREFIX)-1); for( char c : key_string ) { if( isupper(c) ) result += string("-") + char(tolower(c)); else result += c; } return result; }; fc::time_point start_time = fc::time_point::now(); for( const auto& handout : initial_allocation ) { asset amount(handout.second); amount.amount = ((fc::uint128(amount.amount.value) * GRAPHENE_INITIAL_SUPPLY)/total_allocation.value).to_uint64(); if( amount.amount == 0 ) { wlog("Skipping zero allocation to ${k}", ("k", handout.first)); continue; } signed_transaction trx; trx.operations.emplace_back(key_create_operation({asset(), genesis_account.id, handout.first})); relative_key_id_type key_id(0); authority account_authority(1, key_id, 1); account_create_operation cop; cop.name = mangle_to_name(handout.first); cop.registrar = account_id_type(1); cop.active = account_authority; cop.owner = account_authority; cop.memo_key = key_id; trx.operations.push_back(cop); trx.validate(); auto ptrx = apply_transaction(trx, ~0); trx = signed_transaction(); account_id_type account_id(ptrx.operation_results.back().get<object_id_type>()); trx.operations.emplace_back(transfer_operation({ asset(), genesis_account.id, account_id, amount, memo_data()//vector<char>() })); trx.validate(); apply_transaction(trx, ~0); } asset leftovers = get_balance(account_id_type(), asset_id_type()); if( leftovers.amount > 0 ) { modify(*get_index_type<account_balance_index>().indices().get<by_balance>().find(boost::make_tuple(account_id_type(), asset_id_type())), [](account_balance_object& b) { b.adjust_balance(-b.get_balance()); }); modify(core_asset.dynamic_asset_data_id(*this), [&leftovers](asset_dynamic_data_object& d) { d.accumulated_fees += leftovers.amount; }); } fc::microseconds duration = fc::time_point::now() - start_time; ilog("Finished allocating to ${n} accounts in ${t} milliseconds.", ("n", initial_allocation.size())("t", duration.count() / 1000)); } _undo_db.enable(); } FC_LOG_AND_RETHROW() }
void database::init_genesis(const genesis_state_type& genesis_state) { try { FC_ASSERT( genesis_state.initial_timestamp != time_point_sec(), "Must initialize genesis timestamp." ); FC_ASSERT( genesis_state.initial_timestamp.sec_since_epoch() % GRAPHENE_DEFAULT_BLOCK_INTERVAL == 0, "Genesis timestamp must be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL." ); FC_ASSERT(genesis_state.initial_witness_candidates.size() > 0, "Cannot start a chain with zero witnesses."); FC_ASSERT(genesis_state.initial_active_witnesses <= genesis_state.initial_witness_candidates.size(), "initial_active_witnesses is larger than the number of candidate 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); flat_index<block_summary_object>& bsi = get_mutable_index_type< flat_index<block_summary_object> >(); bsi.resize(0xffff+1); // 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>([](account_balance_object& b) { b.balance = GRAPHENE_MAX_SHARE_SUPPLY; }); const account_object& committee_account = create<account_object>( [&](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>( [&](account_statistics_object& s){ s.owner = n.id; }).id; }); FC_ASSERT(committee_account.get_id() == GRAPHENE_COMMITTEE_ACCOUNT); FC_ASSERT(create<account_object>([this](account_object& a) { a.name = "witness-account"; a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).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<account_object>([this](account_object& a) { a.name = "relaxed-committee-account"; a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).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<account_object>([this](account_object& a) { a.name = "null-account"; a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).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<account_object>([this](account_object& a) { a.name = "temp-account"; a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).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); FC_ASSERT(create<account_object>([this](account_object& a) { a.name = "proxy-to-self"; a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).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_PROXY_TO_SELF_ACCOUNT); // Create more special accounts while( true ) { uint64_t id = get_index<account_object>().get_next_id().instance(); if( id >= genesis_state.immutable_parameters.num_special_accounts ) break; const account_object& acct = create<account_object>([&](account_object& a) { a.name = "special-account-" + std::to_string(id); a.statistics = create<account_statistics_object>([&](account_statistics_object& s){s.owner = a.id;}).id; a.owner.weight_threshold = 1; a.active.weight_threshold = 1; a.registrar = a.lifetime_referrer = a.referrer = id; 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; }); FC_ASSERT( acct.get_id() == account_id_type(id) ); remove( acct ); } // Create core asset const asset_dynamic_data_object& dyn_asset = create<asset_dynamic_data_object>([&](asset_dynamic_data_object& a) { a.current_supply = GRAPHENE_MAX_SHARE_SUPPLY; }); const asset_object& core_asset = create<asset_object>( [&]( asset_object& a ) { a.symbol = GRAPHENE_SYMBOL; a.options.max_supply = genesis_state.max_core_supply; a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; a.options.flags = 0; a.options.issuer_permissions = 0; a.issuer = GRAPHENE_NULL_ACCOUNT; 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) ); // Create more special assets while( true ) { uint64_t id = get_index<asset_object>().get_next_id().instance(); if( id >= genesis_state.immutable_parameters.num_special_assets ) break; const asset_dynamic_data_object& dyn_asset = create<asset_dynamic_data_object>([&](asset_dynamic_data_object& a) { a.current_supply = 0; }); const asset_object& asset_obj = create<asset_object>( [&]( asset_object& a ) { a.symbol = "SPECIAL" + std::to_string( id ); a.options.max_supply = 0; a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; a.options.flags = 0; a.options.issuer_permissions = 0; a.issuer = GRAPHENE_NULL_ACCOUNT; 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; }); FC_ASSERT( asset_obj.get_id() == asset_id_type(id) ); remove( asset_obj ); } chain_id_type chain_id = genesis_state.compute_chain_id(); // Create global properties create<global_property_object>([&](global_property_object& p) { 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 p.parameters.current_fees->zero_all_fees(); }); create<dynamic_global_property_object>([&](dynamic_global_property_object& p) { p.time = genesis_state.initial_timestamp; p.dynamic_flags = 0; p.witness_budget = 0; p.recent_slots_filled = fc::uint128::max_value(); }); FC_ASSERT( (genesis_state.immutable_parameters.min_witness_count & 1) == 1, "min_witness_count must be odd" ); FC_ASSERT( (genesis_state.immutable_parameters.min_committee_member_count & 1) == 1, "min_committee_member_count must be odd" ); create<chain_property_object>([&](chain_property_object& p) { p.chain_id = chain_id; p.immutable_parameters = genesis_state.immutable_parameters; } ); create<block_summary_object>([&](block_summary_object&) {}); // Create initial accounts for( const auto& account : genesis_state.initial_accounts ) { account_create_operation cop; cop.name = account.name; cop.registrar = GRAPHENE_TEMP_ACCOUNT; cop.owner = authority(1, account.owner_key, 1); if( account.active_key == public_key_type() ) { cop.active = cop.owner; cop.options.memo_key = account.owner_key; } else { cop.active = authority(1, account.active_key, 1); cop.options.memo_key = account.active_key; } account_id_type account_id(apply_operation(genesis_eval_state, cop).get<object_id_type>()); 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); } } // Helper function to get account ID by name const auto& accounts_by_name = get_index_type<account_index>().indices().get<by_name>(); auto get_account_id = [&accounts_by_name](const string& name) { auto itr = accounts_by_name.find(name); FC_ASSERT(itr != accounts_by_name.end(), "Unable to find account '${acct}'. Did you forget to add a record for it to initial_accounts?", ("acct", name)); return itr->get_id(); }; // Helper function to get asset ID by symbol const auto& assets_by_symbol = get_index_type<asset_index>().indices().get<by_symbol>(); const auto get_asset_id = [&assets_by_symbol](const string& symbol) { auto itr = assets_by_symbol.find(symbol); // TODO: This is temporary for handling BTS snapshot if( symbol == "BTS" ) itr = assets_by_symbol.find(GRAPHENE_SYMBOL); FC_ASSERT(itr != assets_by_symbol.end(), "Unable to find asset '${sym}'. Did you forget to add a record for it to initial_assets?", ("sym", symbol)); return itr->get_id(); }; map<asset_id_type, share_type> total_supplies; map<asset_id_type, share_type> total_debts; // Create initial assets for( const genesis_state_type::initial_asset_type& asset : genesis_state.initial_assets ) { asset_id_type new_asset_id = get_index_type<asset_index>().get_next_id(); total_supplies[ new_asset_id ] = 0; asset_dynamic_data_id_type dynamic_data_id; optional<asset_bitasset_data_id_type> bitasset_data_id; if( asset.is_bitasset ) { int collateral_holder_number = 0; total_debts[ new_asset_id ] = 0; for( const auto& collateral_rec : asset.collateral_records ) { 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<object_id_type>(); modify( owner_account_id(*this).statistics(*this), [&]( account_statistics_object& o ) { o.total_core_in_orders = collateral_rec.collateral; }); create<call_order_object>([&](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, core_asset.id), GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO); }); total_supplies[ 0 ] += collateral_rec.collateral; total_debts[ new_asset_id ] += collateral_rec.debt; ++collateral_holder_number; } bitasset_data_id = create<asset_bitasset_data_object>([&](asset_bitasset_data_object& b) { b.options.short_backing_asset = core_asset.id; b.options.minimum_feeds = GRAPHENE_DEFAULT_MINIMUM_FEEDS; }).id; } dynamic_data_id = create<asset_dynamic_data_object>([&](asset_dynamic_data_object& d) { d.accumulated_fees = asset.accumulated_fees; }).id; total_supplies[ new_asset_id ] += asset.accumulated_fees; create<asset_object>([&](asset_object& a) { a.symbol = asset.symbol; a.options.description = asset.description; a.precision = asset.precision; string issuer_name = asset.issuer_name; a.issuer = get_account_id(issuer_name); a.options.max_supply = asset.max_supply; a.options.flags = witness_fed_asset; a.options.issuer_permissions = charge_market_fee | global_settle | witness_fed_asset | committee_fed_asset; 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 ) { const auto asset_id = get_asset_id(handout.asset_symbol); create<balance_object>([&handout,&get_asset_id,total_allocation,asset_id](balance_object& b) { b.balance = asset(handout.amount, asset_id); b.owner = handout.owner; }); total_supplies[ asset_id ] += handout.amount; } // Create initial vesting balances for( const genesis_state_type::initial_vesting_balance_type& vest : genesis_state.initial_vesting_balances ) { const auto asset_id = get_asset_id(vest.asset_symbol); create<balance_object>([&](balance_object& b) { b.owner = vest.owner; b.balance = asset(vest.amount, asset_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_supplies[ asset_id ] += vest.amount; } if( total_supplies[ 0 ] > 0 ) { adjust_balance(GRAPHENE_COMMITTEE_ACCOUNT, -get_balance(GRAPHENE_COMMITTEE_ACCOUNT,{})); } else { total_supplies[ 0 ] = GRAPHENE_MAX_SHARE_SUPPLY; } const auto& idx = get_index_type<asset_index>().indices().get<by_symbol>(); auto it = idx.begin(); bool has_imbalanced_assets = false; while( it != idx.end() ) { if( it->bitasset_data_id.valid() ) { auto supply_itr = total_supplies.find( it->id ); auto debt_itr = total_debts.find( it->id ); FC_ASSERT( supply_itr != total_supplies.end() ); FC_ASSERT( debt_itr != total_debts.end() ); if( supply_itr->second != debt_itr->second ) { has_imbalanced_assets = true; elog( "Genesis for asset ${aname} is not balanced\n" " Debt is ${debt}\n" " Supply is ${supply}\n", ("debt", debt_itr->second) ("supply", supply_itr->second) ); } } ++it; } FC_ASSERT( !has_imbalanced_assets ); // Save tallied supplies for( const auto& item : total_supplies ) { const auto asset_id = item.first; const auto total_supply = item.second; modify( get( asset_id ), [ & ]( asset_object& asset ) { modify( get( asset.dynamic_asset_data_id ), [ & ]( asset_dynamic_data_object& asset_data ) { asset_data.current_supply = total_supply; } ); } ); } // Create special witness account const witness_object& wit = create<witness_object>([&](witness_object& w) {}); FC_ASSERT( wit.id == GRAPHENE_NULL_WITNESS ); remove(wit); // Create initial witnesses std::for_each(genesis_state.initial_witness_candidates.begin(), genesis_state.initial_witness_candidates.end(), [&](const genesis_state_type::initial_witness_type& witness) { witness_create_operation op; op.witness_account = get_account_id(witness.owner_name); op.block_signing_key = witness.block_signing_key; apply_operation(genesis_eval_state, op); }); // Create initial committee members std::for_each(genesis_state.initial_committee_candidates.begin(), genesis_state.initial_committee_candidates.end(), [&](const genesis_state_type::initial_committee_member_type& member) { committee_member_create_operation op; op.committee_member_account = get_account_id(member.owner_name); apply_operation(genesis_eval_state, op); }); // Create initial workers std::for_each(genesis_state.initial_worker_candidates.begin(), genesis_state.initial_worker_candidates.end(), [&](const genesis_state_type::initial_worker_type& worker) { worker_create_operation op; op.owner = get_account_id(worker.owner_name); op.work_begin_date = genesis_state.initial_timestamp; op.work_end_date = time_point_sec::maximum(); op.daily_pay = worker.daily_pay; op.name = "Genesis-Worker-" + worker.owner_name; op.initializer = vesting_balance_worker_initializer{uint16_t(0)}; apply_operation(genesis_eval_state, std::move(op)); }); // Set active witnesses modify(get_global_properties(), [&](global_property_object& p) { for( uint32_t i = 1; i <= genesis_state.initial_active_witnesses; ++i ) { p.active_witnesses.insert(i); p.witness_accounts.insert(get(witness_id_type(i)).witness_account); } }); // Enable fees modify(get_global_properties(), [&genesis_state](global_property_object& p) { p.parameters.current_fees = genesis_state.initial_parameters.current_fees; }); // Create witness scheduler create<witness_schedule_object>([&]( witness_schedule_object& wso ) { for( const witness_id_type& wid : get_global_properties().active_witnesses ) wso.current_shuffled_witnesses.push_back( wid ); }); debug_dump(); _undo_db.enable(); } FC_CAPTURE_AND_RETHROW() }
/** * This method dumps the state of the blockchain in a semi-human readable form for the * purpose of tracking down funds and mismatches in currency allocation */ void database::debug_dump() { const auto& db = *this; const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db); const auto& balance_index = db.get_index_type<account_balance_index>().indices(); const auto& statistics_index = db.get_index_type<account_stats_index>().indices(); const auto& bids = db.get_index_type<collateral_bid_index>().indices(); const auto& settle_index = db.get_index_type<force_settlement_index>().indices(); map<asset_id_type,share_type> total_balances; map<asset_id_type,share_type> total_debts; share_type core_in_orders; share_type reported_core_in_orders; for( const account_balance_object& a : balance_index ) { // idump(("balance")(a)); total_balances[a.asset_type] += a.balance; } for( const force_settlement_object& s : settle_index ) { total_balances[s.balance.asset_id] += s.balance.amount; } for( const vesting_balance_object& vbo : db.get_index_type< vesting_balance_index >().indices() ) total_balances[ vbo.balance.asset_id ] += vbo.balance.amount; for( const fba_accumulator_object& fba : db.get_index_type< simple_index< fba_accumulator_object > >() ) total_balances[ asset_id_type() ] += fba.accumulated_fba_fees; for( const account_statistics_object& s : statistics_index ) { // idump(("statistics")(s)); reported_core_in_orders += s.total_core_in_orders; } for( const collateral_bid_object& b : bids ) total_balances[b.inv_swan_price.base.asset_id] += b.inv_swan_price.base.amount; for( const limit_order_object& o : db.get_index_type<limit_order_index>().indices() ) { // idump(("limit_order")(o)); auto for_sale = o.amount_for_sale(); if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount; total_balances[for_sale.asset_id] += for_sale.amount; } for( const call_order_object& o : db.get_index_type<call_order_index>().indices() ) { // idump(("call_order")(o)); auto col = o.get_collateral(); if( col.asset_id == asset_id_type() ) core_in_orders += col.amount; total_balances[col.asset_id] += col.amount; total_debts[o.get_debt().asset_id] += o.get_debt().amount; } for( const asset_object& asset_obj : db.get_index_type<asset_index>().indices() ) { total_balances[asset_obj.id] += asset_obj.dynamic_asset_data_id(db).accumulated_fees; total_balances[asset_id_type()] += asset_obj.dynamic_asset_data_id(db).fee_pool; // edump((total_balances[asset_obj.id])(asset_obj.dynamic_asset_data_id(db).current_supply ) ); } if( total_balances[asset_id_type()].value != core_asset_data.current_supply.value ) { FC_THROW( "computed balance of CORE mismatch", ("computed value",total_balances[asset_id_type()].value) ("current supply",core_asset_data.current_supply.value) ); } /* const auto& vbidx = db.get_index_type<simple_index<vesting_balance_object>>(); for( const auto& s : vbidx ) { // idump(("vesting_balance")(s)); } */ }
const asset_object& database::get_core_asset() const { return get(asset_id_type()); }
string pretty_delegate_list( const vector<account_record>& delegate_records, cptr client ) { if( delegate_records.empty() ) return "No delegates found.\n"; FC_ASSERT( client != nullptr ); std::stringstream out; out << std::left; out << std::setw( 6 ) << "ID"; out << std::setw( 32 ) << "NAME (* next in line)"; out << std::setw( 15 ) << "APPROVAL"; out << std::setw( 9 ) << "PRODUCED"; out << std::setw( 9 ) << "MISSED"; out << std::setw( 14 ) << "RELIABILITY"; out << std::setw( 9 ) << "PAY RATE"; out << std::setw( 20 ) << "PAY BALANCE"; out << std::setw( 10 ) << "LAST BLOCK"; out << "\n"; out << pretty_line( 124 ); out << "\n"; const auto current_slot_timestamp = blockchain::get_slot_start_time( blockchain::now() ); const auto head_block_timestamp = client->get_chain()->get_head_block().timestamp; const auto next_slot_time = std::max( current_slot_timestamp, head_block_timestamp + BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC ); const auto& active_delegates = client->get_chain()->get_active_delegates(); const auto next_slot_signee = client->get_chain()->get_slot_signee( next_slot_time, active_delegates ); const auto next_signee_name = next_slot_signee.name; const auto asset_record = client->get_chain()->get_asset_record( asset_id_type() ); FC_ASSERT( asset_record.valid() ); const auto share_supply = asset_record->current_share_supply; for( const auto& delegate_record : delegate_records ) { out << std::setw( 6 ) << delegate_record.id; const auto delegate_name = delegate_record.name; if( delegate_name != next_signee_name ) out << std::setw( 32 ) << pretty_shorten( delegate_name, 31 ); else out << std::setw( 32 ) << pretty_shorten( delegate_name, 29 ) + " *"; out << std::setw( 15 ) << pretty_percent( delegate_record.net_votes(), share_supply, 10 ); const auto num_produced = delegate_record.delegate_info->blocks_produced; const auto num_missed = delegate_record.delegate_info->blocks_missed; out << std::setw( 9 ) << num_produced; out << std::setw( 9 ) << num_missed; out << std::setw( 14 ) << pretty_percent( num_produced, num_produced + num_missed, 2 ); out << std::setw( 9 ) << pretty_percent( delegate_record.delegate_info->pay_rate, 100, 0 ); const auto pay_balance = asset( delegate_record.delegate_info->pay_balance ); out << std::setw( 20 ) << client->get_chain()->to_pretty_asset( pay_balance ); const auto last_block = delegate_record.delegate_info->last_block_num_produced; out << std::setw( 10 ) << ( last_block > 0 ? std::to_string( last_block ) : "NONE" ); out << "\n"; } return out.str(); }
share_type chain_interface::get_delegate_pay_rate()const { const auto base_record = get_asset_record( asset_id_type( 0 ) ); FC_ASSERT( base_record.valid() ); return base_record->collected_fees / (BTS_BLOCKCHAIN_BLOCKS_PER_DAY * 14); }
asset( share_type a = 0, asset_id_type id = asset_id_type() ) :amount(a),asset_id(id){}
/// The unit price for an asset type A is defined to be a price such that for any asset m, m*A=m static price unit_price(asset_id_type a = asset_id_type()) { return price(asset(1, a), asset(1, a)); }