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 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");
        }
    }
}