void burn_operation::evaluate( transaction_evaluation_state& eval_state ) { try { if( message.size() ) FC_ASSERT( amount.asset_id == 0 ); if( amount.asset_id == 0 ) { FC_ASSERT( amount.amount >= BTS_BLOCKCHAIN_MIN_BURN_FEE, "", ("amount",amount) ("BTS_BLOCKCHAIN_MIN_BURN_FEE",BTS_BLOCKCHAIN_MIN_BURN_FEE) ); } oasset_record asset_rec = eval_state._current_state->get_asset_record( amount.asset_id ); FC_ASSERT( asset_rec.valid() ); FC_ASSERT( !asset_rec->is_market_issued() ); asset_rec->current_share_supply -= this->amount.amount; eval_state.sub_balance( address(), this->amount ); eval_state._current_state->store_asset_record( *asset_rec ); if( account_id != 0 ) // you can offer burnt offerings to God if you like... otherwise it must be an account { // TODO: support burning to any OBJECT ID not just accounts const oaccount_record account_rec = eval_state._current_state->get_account_record( abs( this->account_id ) ); FC_ASSERT( account_rec.valid() ); } eval_state._current_state->store_burn_record( burn_record( burn_record_key( {account_id, eval_state.trx.id()} ), burn_record_value( {amount,message,message_signature} ) ) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void ad_operation::evaluate( transaction_evaluation_state& eval_state )const { try { if( this->amount.amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); FC_ASSERT( !message.empty() ); FC_ASSERT( amount.asset_id == 0 ); const size_t message_kb = (message.size() / 1024) + 1; const share_type required_fee = message_kb * BTS_BLOCKCHAIN_MIN_AD_FEE; FC_ASSERT( amount.amount >= required_fee, "Message of size ${s} KiB requires at least ${a} satoshis to be pay!", ("s",message_kb)("a",required_fee) ); // half of the note fees goto collected fees(delegate pay), other go to ad owner eval_state.min_fees[amount.asset_id] += required_fee; FC_ASSERT( owner_account_id != 0 ); const oaccount_record owner_account_rec = eval_state.pending_state()->get_account_record( abs( this->owner_account_id ) ); FC_ASSERT( owner_account_rec.valid() ); auto owner_address = owner_account_rec->active_address(); auto ad_income_balance = eval_state.pending_state()->get_balance_record(withdraw_condition( withdraw_with_signature(owner_address), 0 ).get_address()); if( !ad_income_balance ) ad_income_balance = balance_record( owner_address, asset(0, 0), 0 ); auto ad_pay = amount.amount - required_fee; ad_income_balance->balance += ad_pay; ad_income_balance->last_update = eval_state.pending_state()->now(); ad_income_balance->deposit_date = eval_state.pending_state()->now(); eval_state.pending_state()->store_balance_record( *ad_income_balance ); eval_state.sub_balance( asset(ad_pay, amount.asset_id) ); // checking the signature of the publisher. FC_ASSERT( publisher_account_id != 0 ); const oaccount_record publisher_account_rec = eval_state.pending_state()->get_account_record( abs( this->publisher_account_id ) ); FC_ASSERT( publisher_account_rec.valid() ); eval_state.check_signature( publisher_account_rec->active_key() ); ad_record record; record.index.account_id = owner_account_id; record.index.transaction_id = eval_state.trx.id(); record.publisher_id = publisher_account_id; record.amount = amount; record.message = message; record.signer = message_signature; // the message must be signed by the claimed publisher account FC_ASSERT( publisher_account_rec->active_key() == record.signer_key() ); FC_ASSERT( !eval_state.pending_state()->get_ad_record( record.index ).valid() ); eval_state.pending_state()->store_ad_record( std::move( record ) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void note_operation::evaluate( transaction_evaluation_state& eval_state )const { try { #ifndef WIN32 #warning [HARDFORK] Remove this check after PLS_V0_1_0_FORK_BLOCK_NUM has passed #endif FC_ASSERT( eval_state.pending_state()->get_head_block_num() >= PLS_V0_1_0_FORK_BLOCK_NUM ); if( this->amount.amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); FC_ASSERT( !message->data.empty() ); FC_ASSERT( amount.asset_id == 0 ); const size_t message_kb = (message->data.size() / 1024) + 1; const share_type required_fee = message_kb * BTS_BLOCKCHAIN_MIN_NOTE_FEE; FC_ASSERT( amount.amount >= required_fee, "Message of size ${s} KiB requires at least ${a} satoshis to be burned!", ("s",message_kb)("a",required_fee) ); // 30% of the note fees goto collected fees(delegate pay), other go to the operation pool eval_state.min_fees[amount.asset_id] += amount.amount * 3 / 10; // TODO: instead of burn, the left will go to a fee pool attached to this operation. auto op_reward_record = eval_state.pending_state()->get_operation_reward_record(note_op_type); auto reward_fee = amount.amount - amount.amount * 3 / 10; op_reward_record->fees[amount.asset_id] += reward_fee; eval_state.sub_balance( asset(reward_fee, amount.asset_id) ); eval_state.pending_state()->store_operation_reward_record( *op_reward_record ); // the transaction check the signature of the owner const oaccount_record account_rec = eval_state.pending_state()->get_account_record( abs( this->owner_account_id ) ); FC_ASSERT( account_rec.valid() ); eval_state.check_signature( account_rec->active_key() ); note_record record; record.index.account_id = owner_account_id; record.index.transaction_id = eval_state.trx.id(); record.amount = amount; record.message = message; record.signer = message_signature; // verify the signature of the message, the message signer must be the account_id's active key FC_ASSERT( account_rec->active_key() == record.signer_key() ); FC_ASSERT( !eval_state.pending_state()->get_note_record( record.index ).valid() ); eval_state.pending_state()->store_note_record( std::move( record ) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void burn_operation::evaluate( transaction_evaluation_state& eval_state )const { try { if( this->amount.amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); if( !message.empty() ) FC_ASSERT( amount.asset_id == 0 ); if( amount.asset_id == 0 ) { const size_t message_kb = (message.size() / 1024) + 1; const share_type required_fee = message_kb * BTS_BLOCKCHAIN_MIN_BURN_FEE; FC_ASSERT( amount.amount >= required_fee, "Message of size ${s} KiB requires at least ${a} satoshis to be burned!", ("s",message_kb)("a",required_fee) ); } oasset_record asset_rec = eval_state.pending_state()->get_asset_record( amount.asset_id ); FC_ASSERT( asset_rec.valid() ); FC_ASSERT( !asset_rec->is_market_issued() ); asset_rec->current_supply -= this->amount.amount; eval_state.sub_balance( this->amount ); eval_state.pending_state()->store_asset_record( *asset_rec ); if( account_id != 0 ) // you can offer burnt offerings to God if you like... otherwise it must be an account { const oaccount_record account_rec = eval_state.pending_state()->get_account_record( abs( this->account_id ) ); FC_ASSERT( account_rec.valid() ); } burn_record record; record.index.account_id = account_id; record.index.transaction_id = eval_state.trx.id(); record.amount = amount; record.message = message; record.signer = message_signature; FC_ASSERT( !eval_state.pending_state()->get_burn_record( record.index ).valid() ); eval_state.pending_state()->store_burn_record( std::move( record ) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void add_collateral_operation::evaluate( transaction_evaluation_state& eval_state ) { FC_ASSERT(!"Not implemented for this DAC.\n"); if( this->cover_index.order_price == price() ) FC_CAPTURE_AND_THROW( zero_price, (cover_index.order_price) ); if( this->amount == 0 ) FC_CAPTURE_AND_THROW( zero_amount ); if( this->amount < 0 ) FC_CAPTURE_AND_THROW( negative_deposit ); asset delta_amount = this->get_amount(); eval_state.sub_balance( address(), delta_amount ); // update collateral and call price auto current_cover = eval_state._current_state->get_collateral_record( this->cover_index ); if( NOT current_cover ) FC_CAPTURE_AND_THROW( unknown_market_order, (cover_index) ); current_cover->collateral_balance += delta_amount.amount; // changing the payoff balance changes the call price... so we need to remove the old record // and insert a new one. eval_state._current_state->store_collateral_record( this->cover_index, collateral_record() ); auto new_call_price = asset(current_cover->payoff_balance, delta_amount.asset_id) / asset((current_cover->collateral_balance*3)/4, 0); eval_state._current_state->store_collateral_record( market_index_key( new_call_price, this->cover_index.owner), *current_cover ); auto market_stat = eval_state._current_state->get_market_status( cover_index.order_price.quote_asset_id, cover_index.order_price.base_asset_id ); FC_ASSERT( market_stat, "this should be valid for there to even be a position to cover" ); market_stat->ask_depth += delta_amount.amount; eval_state._current_state->store_market_status( *market_stat ); }
void deposit_operation::evaluate( transaction_evaluation_state& eval_state )const { try { if( this->amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); switch( withdraw_condition_types( this->condition.type ) ) { case withdraw_signature_type: case withdraw_multisig_type: case withdraw_escrow_type: break; default: FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (*this) ); } const balance_id_type deposit_balance_id = this->balance_id(); obalance_record cur_record = eval_state.pending_state()->get_balance_record( deposit_balance_id ); if( !cur_record.valid() ) { cur_record = balance_record( this->condition ); if( this->condition.type == withdraw_escrow_type ) cur_record->meta_data = variant_object("creating_transaction_id", eval_state.trx.id() ); } if( cur_record->balance == 0 ) { cur_record->deposit_date = eval_state.pending_state()->now(); } else { fc::uint128 old_sec_since_epoch( cur_record->deposit_date.sec_since_epoch() ); fc::uint128 new_sec_since_epoch( eval_state.pending_state()->now().sec_since_epoch() ); fc::uint128 avg = (old_sec_since_epoch * cur_record->balance) + (new_sec_since_epoch * this->amount); avg /= (cur_record->balance + this->amount); cur_record->deposit_date = time_point_sec( avg.to_integer() ); } cur_record->balance += this->amount; eval_state.sub_balance( asset( this->amount, cur_record->asset_id() ) ); if( cur_record->condition.asset_id == 0 && cur_record->condition.slate_id ) eval_state.adjust_vote( cur_record->condition.slate_id, this->amount ); cur_record->last_update = eval_state.pending_state()->now(); const oasset_record asset_rec = eval_state.pending_state()->get_asset_record( cur_record->condition.asset_id ); FC_ASSERT( asset_rec.valid() ); if( asset_rec->is_market_issued() ) { FC_ASSERT( cur_record->condition.slate_id == 0 ); } const auto& owners = cur_record->owners(); for( const address& owner : owners ) { FC_ASSERT( asset_rec->address_is_whitelisted( owner ) ); } eval_state.pending_state()->store_balance_record( *cur_record ); } FC_CAPTURE_AND_RETHROW( (*this) ) }