void evaluate_buyback_account_options( const database& db, const buyback_account_options& bbo ) { FC_ASSERT( db.head_block_time() >= HARDFORK_538_TIME ); const asset_object& a = bbo.asset_to_buy(db); GRAPHENE_ASSERT( a.issuer == bbo.asset_to_buy_issuer, account_create_buyback_incorrect_issuer, "Incorrect asset issuer specified in buyback_account_options", ("asset", a)("bbo", bbo) ); GRAPHENE_ASSERT( !a.buyback_account.valid(), account_create_buyback_already_exists, "Cannot create buyback for asset which already has buyback", ("asset", a)("bbo", bbo) ); // TODO: Replace with chain parameter #554 GRAPHENE_ASSERT( bbo.markets.size() < GRAPHENE_DEFAULT_MAX_BUYBACK_MARKETS, account_create_buyback_too_many_markets, "Too many buyback markets", ("asset", a)("bbo", bbo) ); }
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs, const std::function<const authority*(account_id_type)>& get_active, const std::function<const authority*(account_id_type)>& get_owner, uint32_t max_recursion_depth, bool allow_committe, const flat_set<account_id_type>& active_aprovals, const flat_set<account_id_type>& owner_approvals ) { try { flat_set<account_id_type> required_active; flat_set<account_id_type> required_owner; vector<authority> other; for( const auto& op : ops ) operation_get_required_authorities( op, required_active, required_owner, other ); if( !allow_committe ) GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(), invalid_committee_approval, "Committee account may only propose transactions" ); sign_state s(sigs,get_active); s.max_recursion = max_recursion_depth; for( auto& id : active_aprovals ) s.approved_by.insert( id ); for( auto& id : owner_approvals ) s.approved_by.insert( id ); for( const auto& auth : other ) { GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) ); } // fetch all of the top level authorities for( auto id : required_active ) { GRAPHENE_ASSERT( s.check_authority(id) || s.check_authority(get_owner(id)), tx_missing_active_auth, "Missing Active Authority ${id}", ("id",id)("auth",*get_active(id))("owner",*get_owner(id)) ); } for( auto id : required_owner ) { GRAPHENE_ASSERT( owner_approvals.find(id) != owner_approvals.end() || s.check_authority(get_owner(id)), tx_missing_owner_auth, "Missing Owner Authority ${id}", ("id",id)("auth",*get_owner(id)) ); } GRAPHENE_ASSERT( !s.remove_unused_signatures(), tx_irrelevant_sig, "Unnecessary signature(s) detected" ); } FC_CAPTURE_AND_RETHROW( (ops)(sigs) ) }
void fork_database::_push_block(const item_ptr& item) { if( _head ) // make sure the block is within the range that we are caching { FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ), "attempting to push a block that is too old", ("item->num",item->num)("head",_head->num)("max_size",_max_size)); } if( _head && item->previous_id() != block_id_type() ) { auto& index = _index.get<block_id>(); auto itr = index.find(item->previous_id()); GRAPHENE_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain"); item->prev = *itr; } _index.insert(item); if( !_head ) _head = item; else if( item->num > _head->num ) { _head = item; uint32_t min_num = _head->num - std::min( _max_size, _head->num ); // ilog( "min block in fork DB ${n}, max_size: ${m}", ("n",min_num)("m",_max_size) ); auto& num_idx = _index.get<block_num>(); while( num_idx.size() && (*num_idx.begin())->num < min_num ) num_idx.erase( num_idx.begin() ); _unlinked_index.get<block_num>().erase(_head->num - _max_size); } //_push_next( item ); }
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price, asset max_settlement ) { try { FC_ASSERT(call.get_debt().asset_id == settle.balance.asset_id ); FC_ASSERT(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0); auto settle_for_sale = std::min(settle.balance, max_settlement); auto call_debt = call.get_debt(); asset call_receives = std::min(settle_for_sale, call_debt); asset call_pays = call_receives * match_price; asset settle_pays = call_receives; asset settle_receives = call_pays; /** * If the least collateralized call position lacks sufficient * collateral to cover at the match price then this indicates a black * swan event according to the price feed, but only the market * can trigger a black swan. So now we must cancel the forced settlement * object. */ GRAPHENE_ASSERT( call_pays < call.get_collateral(), black_swan_exception, "" ); assert( settle_pays == settle_for_sale || call_receives == call.get_debt() ); fill_order(call, call_pays, call_receives); fill_order(settle, settle_pays, settle_receives); return call_receives; } FC_CAPTURE_AND_RETHROW( (call)(settle)(match_price)(max_settlement) ) }
void fork_database::_push_block(const item_ptr& item) { if( _head ) // make sure the block is within the range that we are caching { FC_ASSERT( item->num > std::max<int64_t>( 0, int64_t(_head->num) - (_max_size) ), "attempting to push a block that is too old", ("item->num",item->num)("head",_head->num)("max_size",_max_size)); FC_ASSERT( item->num < _head->num + MAX_BLOCK_REORDERING ); } if( _head && item->previous_id() != block_id_type() ) { auto& index = _index.get<block_id>(); auto itr = index.find(item->previous_id()); GRAPHENE_ASSERT(itr != index.end(), unlinkable_block_exception, "block does not link to known chain"); FC_ASSERT(!(*itr)->invalid); item->prev = *itr; } _index.insert(item); if( !_head ) _head = item; else if( item->num > _head->num ) { _head = item; _index.get<block_num>().erase(_head->num - _max_size); _unlinked_index.get<block_num>().erase(_head->num - _max_size); } _push_next( item ); }
void_result balance_claim_evaluator::do_evaluate(const balance_claim_operation& op) { database& d = db(); balance = &op.balance_to_claim(d); GRAPHENE_ASSERT( op.balance_owner_key == balance->owner || pts_address(op.balance_owner_key, false, 56) == balance->owner || pts_address(op.balance_owner_key, true, 56) == balance->owner || pts_address(op.balance_owner_key, false, 0) == balance->owner || pts_address(op.balance_owner_key, true, 0) == balance->owner, balance_claim_owner_mismatch, "Balance owner key was specified as '${op}' but balance's actual owner is '${bal}'", ("op", op.balance_owner_key) ("bal", balance->owner) ); if( !(d.get_node_properties().skip_flags & (database::skip_authority_check | database::skip_transaction_signatures)) ) FC_ASSERT(op.total_claimed.asset_id == balance->asset_type()); if( balance->is_vesting_balance() ) { GRAPHENE_ASSERT( balance->vesting_policy->is_withdraw_allowed( { balance->balance, d.head_block_time(), op.total_claimed } ), balance_claim_invalid_claim_amount, "Attempted to claim ${c} from a vesting balance with ${a} available", ("c", op.total_claimed)("a", balance->available(d.head_block_time())) ); GRAPHENE_ASSERT( d.head_block_time() - balance->last_claim_date >= fc::days(1), balance_claim_claimed_too_often, "Genesis vesting balances may not be claimed more than once per day." ); return {}; } FC_ASSERT(op.total_claimed == balance->balance); return {}; }
virtual operation_result evaluate(const operation& o) final override { auto* eval = static_cast<DerivedEvaluator*>(this); const auto& op = o.get<typename DerivedEvaluator::operation_type>(); prepare_fee(op.fee_payer(), op.fee); GRAPHENE_ASSERT( core_fee_paid >= db().current_fee_schedule().calculate_fee( op ).amount, insufficient_fee, "Insufficient Fee Paid", ("core_fee_paid",core_fee_paid)("required",db().current_fee_schedule().calculate_fee( op ).amount) ); return eval->do_evaluate(op); }
/** * Removes the most recent block from the database and * undoes any changes it made. */ void database::pop_block() { try { _pending_tx_session.reset(); auto head_id = head_block_id(); optional<signed_block> head_block = fetch_block_by_id( head_id ); GRAPHENE_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" ); _fork_db.pop_block(); pop_undo(); _popped_tx.insert( _popped_tx.begin(), head_block->transactions.begin(), head_block->transactions.end() ); } FC_CAPTURE_AND_RETHROW() }
flat_set<public_key_type> signed_transaction::get_signature_keys( const chain_id_type& chain_id )const { try { auto d = sig_digest( chain_id ); flat_set<public_key_type> result; for( const auto& sig : signatures ) { GRAPHENE_ASSERT( result.insert( fc::ecc::public_key(sig,d) ).second, tx_duplicate_sig, "Duplicate Signature detected" ); } return result; } FC_CAPTURE_AND_RETHROW() }
void database::update_global_dynamic_data( const signed_block& b ) { const dynamic_global_property_object& _dgp = dynamic_global_property_id_type(0)(*this); uint32_t missed_blocks = get_slot_at_time( b.timestamp ); assert( missed_blocks != 0 ); missed_blocks--; // dynamic global properties updating modify( _dgp, [&]( dynamic_global_property_object& dgp ){ if( BOOST_UNLIKELY( b.block_num() == 1 ) ) dgp.recently_missed_count = 0; else if( _checkpoints.size() && _checkpoints.rbegin()->first >= b.block_num() ) dgp.recently_missed_count = 0; else if( missed_blocks ) dgp.recently_missed_count += GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT*missed_blocks; else if( dgp.recently_missed_count > GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT ) dgp.recently_missed_count -= GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT; else if( dgp.recently_missed_count > 0 ) dgp.recently_missed_count--; dgp.head_block_number = b.block_num(); dgp.head_block_id = b.id(); dgp.time = b.timestamp; dgp.current_witness = b.witness; dgp.recent_slots_filled = ( (dgp.recent_slots_filled << 1) + 1) << missed_blocks; dgp.current_aslot += missed_blocks+1; }); if( !(get_node_properties().skip_flags & skip_undo_history_check) ) { GRAPHENE_ASSERT( _dgp.recently_missed_count < GRAPHENE_MAX_UNDO_HISTORY, undo_database_exception, "The database does not have enough undo history to support a blockchain with so many missed blocks. " "Please add a checkpoint if you would like to continue applying blocks beyond this point.", ("recently_missed",_dgp.recently_missed_count)("max_undo",GRAPHENE_MAX_UNDO_HISTORY) ); } _undo_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY ); _fork_db.set_max_size( _dgp.recently_missed_count + GRAPHENE_MIN_UNDO_HISTORY ); }