void user_auction_claim_operation::evaluate( transaction_evaluation_state& eval_state )
    { try {
        FC_ASSERT( !"This operation is not enabled yet!" );

        auto chain = eval_state._current_state;   
        auto obj = chain->get_object_record( this->auction_id );
        FC_ASSERT( obj.valid(), "No such auction." );
        auto auction = obj->as<user_auction_record>();
        FC_ASSERT( auction.is_complete( *chain ), "Auction is not over yet." );
        if( this->claim_balance )
        {
            FC_ASSERT( NOT auction.balance_claimed,
                    "Those auction winnings have already been claimed." );
            eval_state.check_update_permission( auction.beneficiary );
            eval_state.add_balance( auction.previous_bid );
            auction.balance_claimed = true;
        }
        if( this->claim_object ) // set the item's owner to the winner
        {
            FC_ASSERT( NOT auction.object_claimed, "That object has already been claimed." );
            eval_state.check_update_permission( auction.previous_bidder );
            auto item = chain->get_object_record( auction.item );
            FC_ASSERT( item->owner_object == auction._id, "An auction was being held for an item owned by someone else?");
            item->owner_object = auction.previous_bidder;
            chain->store_object_record( *item );
            auction.object_claimed = true;
        }
        chain->store_object_record( object_record( auction ) );
    } FC_CAPTURE_AND_RETHROW( (eval_state)(*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 transaction_validator::validate_name_output( const trx_output& out, 
                                                   transaction_evaluation_state& state,
                                                   const block_evaluation_state_ptr& block_state )
 {
     auto claim = out.as<claim_name_output>(); 
     block_state->add_name_output( claim );
     if( !state.has_name_input( claim ) )
     {
        auto name_rec = _db->lookup_name( claim.name );
        FC_ASSERT( !name_rec );
     }
     FC_ASSERT( out.amount.unit == 0 );
     state.add_output_asset( out.amount );
 }
   void transaction_validator::validate_signature_input( const meta_trx_input& in, 
                                                         transaction_evaluation_state& state,
                                                         const block_evaluation_state_ptr& block_state )
   {
       auto claim = in.output.as<claim_by_signature_output>(); 
       FC_ASSERT( state.has_signature( claim.owner ), "", ("owner",claim.owner)("sigs",state.sigs) );
       state.add_input_asset( in.output.amount );

       if( in.output.amount.unit == 0 )
       {
          accumulate_votes( in.output.amount.get_rounded_amount(), in.source.block_num, state );
          block_state->add_input_delegate_votes( in.delegate_id, in.output.amount );
          block_state->add_output_delegate_votes( state.trx.vote, in.output.amount );
       }
   }
    void data_operation::evaluate( transaction_evaluation_state& eval_state )const
    {
#ifndef WIN32
#warning [SOFTFORK] Remove this check after BTS_V0_9_0_FORK_BLOCK_NUM has passed
#endif
      FC_ASSERT( eval_state.pending_state()->get_head_block_num() >= BTS_V0_9_0_FORK_BLOCK_NUM );
    }
   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) ) }
Exemple #7
0
 void domain_update_signin_operation::evaluate( transaction_evaluation_state& eval_state )
 {
     auto odomain_rec = eval_state._current_state->get_domain_record( this->domain_name );
     auto now = eval_state._current_state->now().sec_since_epoch();
     FC_ASSERT( odomain_rec.valid(), "Trying to update domain which does not exist" );
     FC_ASSERT( odomain_rec->get_true_state(now) == domain_record::owned,
                "Attempting to update a domain which is not in 'owned' state");
     FC_ASSERT( eval_state.check_signature( odomain_rec->owner ), "Update not signed by owner" );
     odomain_rec->signin_key = this->signin_key;
     odomain_rec->last_update = eval_state._current_state->now().sec_since_epoch();
     eval_state._current_state->store_domain_record( *odomain_rec );
 }
    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) ) }
Exemple #9
0
   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 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) ) }
   transaction_summary transaction_validator::on_evaluate( transaction_evaluation_state& state, 
                                                           const block_evaluation_state_ptr& block_state )
   {
       transaction_summary sum;

       state.inputs = _db->fetch_inputs( state.trx.inputs );
       auto trx_delegate = _db->lookup_delegate( state.trx.vote );
       FC_ASSERT( !!trx_delegate, "unable to find delegate id ${id}", ("id",state.trx.vote) );

       /** make sure inputs are unique */
       std::unordered_set<output_reference> unique_inputs;
       for( auto in : state.trx.inputs )
       {
          FC_ASSERT( unique_inputs.insert( in.output_ref ).second, 
              "transaction references same output more than once.", ("trx",state.trx) )
       }

       /** validate all inputs */
       for( auto in : state.inputs ) 
       {
          FC_ASSERT( !in.meta_output.is_spent(), "", ("trx",state.trx) );
          validate_input( in, state, block_state );
       }


       /** validate all inputs */
       for( auto out : state.trx.outputs ) 
          validate_output( out, state, block_state );

       state.balance_assets();

       sum.valid_votes      = state.valid_votes;
       sum.invalid_votes    = state.invalid_votes;
       sum.spent            = state.spent;
       sum.fees             = state.get_total_in(0) - state.get_total_out(0);
       if( state.get_required_fees() >= 0 )
       {
          FC_ASSERT( sum.fees >= state.get_required_fees(0), "",
                     ("fees",sum.fees)("required",state.get_required_fees()));
       }
       return sum;
   }
void withdraw_operation::evaluate_v3( transaction_evaluation_state& eval_state )
{ try {
   if( eval_state._current_state->get_head_block_num() < BTS_V0_4_15_FORK_BLOCK_NUM )
      return evaluate_v2( eval_state );

    if( this->amount <= 0 )
       FC_CAPTURE_AND_THROW( negative_deposit, (amount) );

   obalance_record current_balance_record = eval_state._current_state->get_balance_record( this->balance_id );

   if( !current_balance_record )
      FC_CAPTURE_AND_THROW( unknown_balance_record, (balance_id) );

   if( this->amount > current_balance_record->balance ) // Some withdraw conditions require extra checks (e.g. vesting condition)
      FC_CAPTURE_AND_THROW( insufficient_funds,
                            (current_balance_record)
                            (amount)
                            (current_balance_record->balance - amount) );

   switch( (withdraw_condition_types)current_balance_record->condition.type )
   {
      case withdraw_signature_type:
      {
         auto owner = current_balance_record->condition.as<withdraw_with_signature>().owner;
         if( !eval_state.check_signature( owner ) )
             FC_CAPTURE_AND_THROW( missing_signature, (owner) );
         break;
      }

      default:
         FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (current_balance_record->condition) );
   }
   // update delegate vote on withdrawn account..

   if( current_balance_record->condition.asset_id == 0 && current_balance_record->condition.delegate_slate_id )
      eval_state.adjust_vote( current_balance_record->condition.delegate_slate_id, -this->amount );

   auto asset_rec = eval_state._current_state->get_asset_record( current_balance_record->condition.asset_id );
   FC_ASSERT( asset_rec.valid() );
   if( asset_rec->is_market_issued() )
   {
      auto yield = current_balance_record->calculate_yield_v1( eval_state._current_state->now(),
                                                               current_balance_record->balance,
                                                               asset_rec->collected_fees,
                                                               asset_rec->current_share_supply );

      if( yield.amount > 0 )
      {
         asset_rec->collected_fees       -= yield.amount;
         current_balance_record->balance += yield.amount;
         current_balance_record->deposit_date = eval_state._current_state->now();
         eval_state.yield[current_balance_record->condition.asset_id] += yield.amount;
         eval_state._current_state->store_asset_record( *asset_rec );
      }
   }

   current_balance_record->balance -= this->amount;
   current_balance_record->last_update = eval_state._current_state->now();

   eval_state._current_state->store_balance_record( *current_balance_record );
   eval_state.add_balance( asset(this->amount, current_balance_record->condition.asset_id) );
} FC_CAPTURE_AND_RETHROW( (*this) ) }
   void update_balance_vote_operation::evaluate( transaction_evaluation_state& eval_state )const
   { try {
      auto current_balance_record = eval_state.pending_state()->get_balance_record( this->balance_id );
      FC_ASSERT( current_balance_record.valid(), "No such balance!" );
      FC_ASSERT( current_balance_record->condition.asset_id == 0, "Only BTS balances can have restricted owners." );
      FC_ASSERT( current_balance_record->condition.type == withdraw_signature_type, "Restricted owners not enabled for anything but basic balances" );

      auto last_update_secs = current_balance_record->last_update.sec_since_epoch();
      ilog("last_update_secs is: ${secs}", ("secs", last_update_secs) );

      auto balance = current_balance_record->balance;
      auto fee = BTS_BLOCKCHAIN_PRECISION / 2;
      FC_ASSERT( balance > fee );

      auto asset_rec = eval_state.pending_state()->get_asset_record( current_balance_record->condition.asset_id );
      if( asset_rec->is_market_issued() ) FC_ASSERT( current_balance_record->condition.slate_id == 0 );

      if( current_balance_record->condition.slate_id )
      {
          eval_state.adjust_vote( current_balance_record->condition.slate_id, -balance );
      }
      current_balance_record->balance -= balance;
      current_balance_record->last_update = eval_state.pending_state()->now();

      ilog("I'm storing a balance record whose last update is: ${secs}", ("secs", current_balance_record->last_update) );
      eval_state.pending_state()->store_balance_record( *current_balance_record );

      auto new_restricted_owner = current_balance_record->restricted_owner;
      auto new_slate = current_balance_record->condition.slate_id;

      if( this->new_restricted_owner.valid() && (this->new_restricted_owner != new_restricted_owner) )
      {
          ilog("@n new restricted owner specified and its not the existing one");
          for( const auto& owner : current_balance_record->owners() ) //eventually maybe multisig can delegate vote
          {
              if( !eval_state.check_signature( owner ) )
                  FC_CAPTURE_AND_THROW( missing_signature, (owner) );
          }
          new_restricted_owner = this->new_restricted_owner;
          new_slate = this->new_slate;
      }
      else // NOT this->new_restricted_owner.valid() || (this->new_restricted_owner == new_restricted_owner)
      {
          auto restricted_owner = current_balance_record->restricted_owner;
          /*
          FC_ASSERT( restricted_owner.valid(),
                     "Didn't specify a new restricted owner, but one currently exists." );
                     */
          ilog( "@n now: ${secs}", ("secs", eval_state.pending_state()->now().sec_since_epoch()) );
          ilog( "@n last update: ${secs}", ("secs", last_update_secs ) );
          FC_ASSERT( eval_state.pending_state()->now().sec_since_epoch() - last_update_secs
                     >= BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC,
                     "You cannot update your vote this frequently with only the voting key!" );

          if( NOT eval_state.check_signature( *restricted_owner ) )
          {
              const auto& owners = current_balance_record->owners();
              for( const auto& owner : owners ) //eventually maybe multisig can delegate vote
              {
                  if( NOT eval_state.check_signature( owner ) )
                      FC_CAPTURE_AND_THROW( missing_signature, (owner) );
              }
          }
          new_slate = this->new_slate;
      }

      const auto owner = current_balance_record->owner();
      FC_ASSERT( owner.valid() );
      withdraw_condition new_condition( withdraw_with_signature( *owner ), 0, new_slate );
      balance_record newer_balance_record( new_condition );
      auto new_balance_record = eval_state.pending_state()->get_balance_record( newer_balance_record.id() );
      if( !new_balance_record.valid() )
          new_balance_record = current_balance_record;
      new_balance_record->condition = new_condition;

      if( new_balance_record->balance == 0 )
      {
         new_balance_record->deposit_date = eval_state.pending_state()->now();
      }
      else
      {
         fc::uint128 old_sec_since_epoch( current_balance_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 * new_balance_record->balance) + (new_sec_since_epoch * balance);
         avg /= (new_balance_record->balance + balance);

         new_balance_record->deposit_date = time_point_sec( avg.to_integer() );
      }

      new_balance_record->last_update = eval_state.pending_state()->now();
      new_balance_record->balance += (balance - fee);
      new_balance_record->restricted_owner = new_restricted_owner;

      eval_state.add_balance( asset(fee, 0) );

      // update delegate vote on deposited account..
      if( new_balance_record->condition.slate_id )
         eval_state.adjust_vote( new_balance_record->condition.slate_id, (balance-fee) );

      ilog("I'm storing a balance record whose last update is: ${secs}", ("secs", new_balance_record->last_update) );
      eval_state.pending_state()->store_balance_record( *new_balance_record );

   } FC_CAPTURE_AND_RETHROW( (*this) ) }
   void release_escrow_operation::evaluate( transaction_evaluation_state& eval_state )const
   { try {
      auto escrow_balance_record = eval_state.pending_state()->get_balance_record( this->escrow_id );
      FC_ASSERT( escrow_balance_record.valid() );

      if( this->amount_to_receiver < 0 )
         FC_CAPTURE_AND_THROW( negative_withdraw, (amount_to_receiver) );

      if( this->amount_to_sender < 0 )
         FC_CAPTURE_AND_THROW( negative_withdraw, (amount_to_sender) );

      if( !eval_state.check_signature( this->released_by ) )
         FC_ASSERT( false, "transaction not signed by releasor" );

      auto escrow_condition = escrow_balance_record->condition.as<withdraw_with_escrow>();
      auto total_released = uint64_t(amount_to_sender) + uint64_t(amount_to_receiver);

      FC_ASSERT( total_released <= escrow_balance_record->balance );
      FC_ASSERT( total_released >= amount_to_sender ); // check for addition overflow
      FC_ASSERT( total_released >= amount_to_receiver ); // check for addition overflow

      escrow_balance_record->balance -= total_released;
      auto asset_rec = eval_state.pending_state()->get_asset_record( escrow_balance_record->condition.asset_id );

      if( amount_to_sender > 0 )
          FC_ASSERT( asset_rec->address_is_whitelisted( escrow_condition.sender ) );
      if( amount_to_receiver > 0 )
          FC_ASSERT( asset_rec->address_is_whitelisted( escrow_condition.receiver ) );

      const bool authority_is_retracting = asset_rec->flag_is_active( asset_record::retractable_balances )
                                           && eval_state.verify_authority( asset_rec->authority );

      if( escrow_condition.sender == this->released_by )
      {
         FC_ASSERT( amount_to_sender == 0 );
         FC_ASSERT( amount_to_receiver <= escrow_balance_record->balance );

         if( !eval_state.check_signature( escrow_condition.sender ) && !authority_is_retracting)
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.sender) );

         balance_record new_balance_record( escrow_condition.receiver,
                                            asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                            escrow_balance_record->slate_id() );
         auto current_receiver_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

         if( current_receiver_balance )
            current_receiver_balance->balance += amount_to_receiver;
         else
            current_receiver_balance = new_balance_record;

          eval_state.pending_state()->store_balance_record( *current_receiver_balance );
      }
      else if( escrow_condition.receiver == this->released_by )
      {
         FC_ASSERT( amount_to_receiver == 0 );
         FC_ASSERT( amount_to_sender <= escrow_balance_record->balance );

         if( !eval_state.check_signature( escrow_condition.receiver ) && !authority_is_retracting)
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.receiver) );

         balance_record new_balance_record( escrow_condition.sender,
                                            asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                            escrow_balance_record->slate_id() );
         auto current_sender_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

         if( current_sender_balance )
            current_sender_balance->balance += amount_to_sender;
         else
            current_sender_balance = new_balance_record;

         eval_state.pending_state()->store_balance_record( *current_sender_balance );
      }
      else if( escrow_condition.escrow == this->released_by )
      {
         if( !eval_state.check_signature( escrow_condition.escrow ) && !authority_is_retracting )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.escrow) );
         // get a balance record for the receiver, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.receiver,
                                               asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_receiver_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

            if( current_receiver_balance )
               current_receiver_balance->balance += amount_to_receiver;
            else
               current_receiver_balance = new_balance_record;
            eval_state.pending_state()->store_balance_record( *current_receiver_balance );
         }
         //  get a balance record for the sender, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.sender,
                                               asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_sender_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

            if( current_sender_balance )
               current_sender_balance->balance += amount_to_sender;
            else
               current_sender_balance = new_balance_record;
            eval_state.pending_state()->store_balance_record( *current_sender_balance );
         }
      }
      else if( address() == this->released_by )
      {
         if( !eval_state.check_signature( escrow_condition.sender ) && !authority_is_retracting)
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.sender) );
         if( !eval_state.check_signature( escrow_condition.receiver ) && !authority_is_retracting)
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.receiver) );
         // get a balance record for the receiver, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.receiver,
                                               asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_receiver_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

            if( current_receiver_balance )
               current_receiver_balance->balance += amount_to_receiver;
            else
               current_receiver_balance = new_balance_record;
            eval_state.pending_state()->store_balance_record( *current_receiver_balance );
         }
         //  get a balance record for the sender, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.sender,
                                               asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_sender_balance = eval_state.pending_state()->get_balance_record( new_balance_record.id());

            if( current_sender_balance )
               current_sender_balance->balance += amount_to_sender;
            else
               current_sender_balance = new_balance_record;
            eval_state.pending_state()->store_balance_record( *current_sender_balance );
         }
      }
      else
      {
          FC_ASSERT( false, "not released by a party to the escrow transaction" );
      }

      eval_state.pending_state()->store_balance_record( *escrow_balance_record );
   } FC_CAPTURE_AND_RETHROW( (*this) ) }
 void transaction_validator::validate_pts_signature_output( const trx_output& out, 
                                                            transaction_evaluation_state& state,
                                                            const block_evaluation_state_ptr& block_state )
 {
     state.add_output_asset( out.amount );
 }
void dns_transaction_validator::validate_domain_output(const trx_output& out, transaction_evaluation_state& state)
{
    auto dns_state = dynamic_cast<dns_tx_evaluation_state&>(state);
    FC_ASSERT( ! dns_state.seen_domain_output,
               "More than one domain claim output in one tx: ${tx}", ("tx", state.trx) );
    dns_state.seen_domain_output = true;

    // "name" and "value" length limits
    auto dns_out = out.as<claim_domain_output>();

    dns_db* db = dynamic_cast<dns_db*>(_db);
    FC_ASSERT( db != nullptr );


    /* If we haven't seen a domain input then the only valid output is a new
     * domain auction.
     */
    if (! dns_state.seen_domain_input)
    {
        // name doesn't already exist  (not in DB OR older than 1 year)
        if ( db->has_dns_record(dns_out.name) )
        {
            auto old_record = db->get_dns_record(dns_out.name);
            auto old_tx_id = old_record.last_update_ref.trx_hash;
            auto block_num = db->fetch_trx_num(old_tx_id).block_num;
            auto current_block = db->head_block_num();

            if (current_block - block_num < BTS_BLOCKCHAIN_BLOCKS_PER_YEAR)
            {
                FC_ASSERT(!"Name already exists (and is younger than 1 block-year)");
            }
        }
        FC_ASSERT(dns_out.flags == claim_domain_output::for_auction,
                  "New auction started with for_auction flag not set");
        return;
    }


    /* Otherwise, the transaction must have a domain input and it must exist
     * in the database, and it can't be expired
     */
    //TODO do this just from the input without looking into the DB?
    FC_ASSERT( db->has_dns_record(dns_out.name),
               "Transaction references a name that doesn't exist");
    auto old_record = db->get_dns_record(dns_out.name);
    auto old_tx_id = old_record.last_update_ref.trx_hash;
    auto block_num = db->fetch_trx_num(old_tx_id).block_num;
    auto current_block = db->head_block_num();
    auto block_age = current_block - block_num;
    FC_ASSERT( block_age < BTS_BLOCKCHAIN_BLOCKS_PER_YEAR,
               "Domain transaction references an expired domain as an input");

    FC_ASSERT(dns_out.name == dns_state.dns_claimed.name,
              "bid transaction refers to different input and output names");


    // case on state of claimed output
    //   * if auction is over (not_for_sale OR output is older than 3 days)
    if (dns_out.flags == claim_domain_output::not_for_sale
            || block_age >= 3 * BTS_BLOCKCHAIN_BLOCKS_PER_DAY)
    {
        // If you're the owner, do whatever you like!
        if (! state.has_signature(dns_out.owner) )
        {
            FC_ASSERT(false, "Domain tx requiring signature doesn't have it: ${tx}",
                      ("tx", state.trx));
        }

    } else {
        // Currently in an auction
        FC_ASSERT(dns_out.flags == claim_domain_output::for_auction,
                  "bid made without keeping for_auction flag");
        //TODO use macros in dns_config.hpp instead of hard-coded constants
        //TODO restore
        FC_ASSERT(out.amount.get_rounded_amount() >=
                  (11 * dns_state.claimed.amount.get_rounded_amount()) / 10,
                  "Bid was too small: ${trx}", ("trx", state.trx) );
        // half of difference goes to fee
        dns_state.add_required_fees((out.amount - dns_state.claimed.amount) / 2);

        // check for output to past owner
        bool found = false;
        for (auto other_out : state.trx.outputs)
        {
            bool right_claim = other_out.claim_func == claim_by_signature;
            bool enough = (other_out.amount ==
                           dns_state.claimed.amount + (out.amount - dns_state.claimed.amount / 2));
            bool to_owner = right_claim &&
                            other_out.as<claim_by_signature_output>().owner == dns_state.dns_claimed.owner;
            if (right_claim && enough && to_owner)
            {
                found = true;
                break;
            }
        }
        if (!found)
        {
            FC_ASSERT(!"Bid did not pay enough to previous owner");
        }
    }
}
   void withdraw_operation::evaluate( transaction_evaluation_state& eval_state )const
   { try {
       if( this->amount <= 0 )
          FC_CAPTURE_AND_THROW( negative_withdraw, (amount) );

      obalance_record current_balance_record = eval_state.pending_state()->get_balance_record( this->balance_id );
      if( !current_balance_record.valid() )
         FC_CAPTURE_AND_THROW( unknown_balance_record, (balance_id) );

      if( this->amount > current_balance_record->get_spendable_balance( eval_state.pending_state()->now() ).amount )
         FC_CAPTURE_AND_THROW( insufficient_funds, (current_balance_record)(amount) );

      auto asset_rec = eval_state.pending_state()->get_asset_record( current_balance_record->condition.asset_id );
      FC_ASSERT( asset_rec.valid() );

      const bool authority_is_retracting = asset_rec->flag_is_active( asset_record::retractable_balances )
                                           && eval_state.verify_authority( asset_rec->authority );

      if( !authority_is_retracting )
      {
         FC_ASSERT( !asset_rec->flag_is_active( asset_record::halted_withdrawals ) );

         switch( (withdraw_condition_types)current_balance_record->condition.type )
         {
            case withdraw_signature_type:
            {
                const withdraw_with_signature condition = current_balance_record->condition.as<withdraw_with_signature>();
                const address owner = condition.owner;
                if( !eval_state.check_signature( owner ) )
                    FC_CAPTURE_AND_THROW( missing_signature, (owner) );
                break;
            }

            case withdraw_vesting_type:
            {
                const withdraw_vesting condition = current_balance_record->condition.as<withdraw_vesting>();
                const address owner = condition.owner;
                if( !eval_state.check_signature( owner ) )
                    FC_CAPTURE_AND_THROW( missing_signature, (owner) );
                break;
            }

            case withdraw_multisig_type:
            {
               auto multisig = current_balance_record->condition.as<withdraw_with_multisig>();

               uint32_t valid_signatures = 0;
               for( const auto& sig : multisig.owners )
                    valid_signatures += eval_state.check_signature( sig );

               if( valid_signatures < multisig.required )
                   FC_CAPTURE_AND_THROW( missing_signature, (valid_signatures)(multisig) );
               break;
            }

            default:
               FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (current_balance_record->condition) );
         }
      }

      // update delegate vote on withdrawn account..
      if( current_balance_record->condition.asset_id == 0 && current_balance_record->condition.slate_id )
         eval_state.adjust_vote( current_balance_record->condition.slate_id, -this->amount );

      if( asset_rec->is_market_issued() )
      {
         auto yield = current_balance_record->calculate_yield( eval_state.pending_state()->now(),
                                                               current_balance_record->balance,
                                                               asset_rec->collected_fees,
                                                               asset_rec->current_supply );
         if( yield.amount > 0 )
         {
            asset_rec->collected_fees       -= yield.amount;
            current_balance_record->balance += yield.amount;
            current_balance_record->deposit_date = eval_state.pending_state()->now();
            eval_state.yield_claimed[ current_balance_record->asset_id() ] += yield.amount;
            eval_state.pending_state()->store_asset_record( *asset_rec );
         }
      }

      current_balance_record->balance -= this->amount;
      current_balance_record->last_update = eval_state.pending_state()->now();
      eval_state.pending_state()->store_balance_record( *current_balance_record );

      if( asset_rec->withdrawal_fee != 0 && !eval_state.verify_authority( asset_rec->authority ) )
          eval_state.min_fees[ asset_rec->id ] = std::max( asset_rec->withdrawal_fee, eval_state.min_fees[ asset_rec->id ] );

      eval_state.add_balance( asset( this->amount, current_balance_record->condition.asset_id ) );
   } FC_CAPTURE_AND_RETHROW( (*this) ) }
   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) ) }
   void release_escrow_operation::evaluate( transaction_evaluation_state& eval_state )
   { try {
      FC_ASSERT( !"This operation is not enabled yet!" );

      auto escrow_balance_record = eval_state._current_state->get_balance_record( this->escrow_id );
      FC_ASSERT( escrow_balance_record.valid() );

      if( !eval_state.check_signature( this->released_by ) )
         FC_ASSERT( !"transaction not signed by releasor" );

      auto escrow_condition = escrow_balance_record->condition.as<withdraw_with_escrow>();
      auto total_released = amount_to_sender + amount_to_receiver;

      FC_ASSERT( total_released <= escrow_balance_record->balance );
      FC_ASSERT( total_released >= amount_to_sender ); // check for addition overflow

      escrow_balance_record->balance -= total_released;
      auto asset_rec = eval_state._current_state->get_asset_record( escrow_balance_record->condition.asset_id );
      if( asset_rec->is_restricted() )
      {
         FC_ASSERT( eval_state._current_state->get_authorization( escrow_balance_record->condition.asset_id, escrow_condition.receiver ) );
      }
      if( asset_rec->is_retractable() )
      {
         if( eval_state.verify_authority( asset_rec->authority ) )
         {
            //
         }
      }

      if( escrow_condition.sender == this->released_by )
      {
         FC_ASSERT( amount_to_sender == 0 );
         FC_ASSERT( amount_to_receiver <= escrow_balance_record->balance );

         if( !eval_state.check_signature( escrow_condition.sender ) )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.sender) );

         balance_record new_balance_record( escrow_condition.receiver,
                                            asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                            escrow_balance_record->slate_id() );
         auto current_receiver_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

         if( current_receiver_balance )
            current_receiver_balance->balance += amount_to_receiver;
         else
            current_receiver_balance = new_balance_record;

          eval_state._current_state->store_balance_record( *current_receiver_balance );
      }
      else if( escrow_condition.receiver == this->released_by )
      {
         FC_ASSERT( amount_to_receiver == 0 );
         FC_ASSERT( amount_to_sender <= escrow_balance_record->balance );

         if( !eval_state.check_signature( escrow_condition.receiver ) )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.receiver) );

         balance_record new_balance_record( escrow_condition.sender,
                                            asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                            escrow_balance_record->slate_id() );
         auto current_sender_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

         if( current_sender_balance )
            current_sender_balance->balance += amount_to_sender;
         else
            current_sender_balance = new_balance_record;

         eval_state._current_state->store_balance_record( *current_sender_balance );
      }
      else if( escrow_condition.escrow == this->released_by )
      {
         if( !eval_state.check_signature( escrow_condition.escrow ) )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.escrow) );
         // get a balance record for the receiver, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.receiver,
                                               asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_receiver_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

            if( current_receiver_balance )
               current_receiver_balance->balance += amount_to_receiver;
            else
               current_receiver_balance = new_balance_record;
            eval_state._current_state->store_balance_record( *current_receiver_balance );
         }
         //  get a balance record for the sender, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.sender,
                                               asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_sender_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

            if( current_sender_balance )
               current_sender_balance->balance += amount_to_sender;
            else
               current_sender_balance = new_balance_record;
            eval_state._current_state->store_balance_record( *current_sender_balance );
         }
      }
      else if( address() == this->released_by )
      {
         if( !eval_state.check_signature( escrow_condition.sender ) )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.sender) );
         if( !eval_state.check_signature( escrow_condition.receiver ) )
             FC_CAPTURE_AND_THROW( missing_signature, (escrow_condition.receiver) );
         // get a balance record for the receiver, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.receiver,
                                               asset( amount_to_receiver, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_receiver_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

            if( current_receiver_balance )
               current_receiver_balance->balance += amount_to_receiver;
            else
               current_receiver_balance = new_balance_record;
            eval_state._current_state->store_balance_record( *current_receiver_balance );
         }
         //  get a balance record for the sender, create it if necessary and deposit funds
         {
            balance_record new_balance_record( escrow_condition.sender,
                                               asset( amount_to_sender, escrow_balance_record->asset_id() ),
                                               escrow_balance_record->slate_id() );
            auto current_sender_balance = eval_state._current_state->get_balance_record( new_balance_record.id());

            if( current_sender_balance )
               current_sender_balance->balance += amount_to_sender;
            else
               current_sender_balance = new_balance_record;
            eval_state._current_state->store_balance_record( *current_sender_balance );
         }
      }
      else
      {
          FC_ASSERT( !"not released by a party to the escrow transaction" );
      }

      eval_state._current_state->store_balance_record( *escrow_balance_record );
   } FC_CAPTURE_AND_RETHROW( (*this) ) }