bool TransactionPrefixImpl::validateInputs() const {
  return check_inputs_types_supported(m_txPrefix) &&
          check_inputs_overflow(m_txPrefix) &&
          checkInputsKeyimagesDiff(m_txPrefix) &&
          checkMultisignatureInputsDiff(m_txPrefix);
}
Exemplo n.º 2
0
//---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block)
{

    //#9Protection from big transaction flood
    if(!kept_by_block && blob_size > m_blockchain.get_current_comulative_blocksize_limit() / 2)
    {
        LOG_PRINT_L0("transaction is too big for current transaction flow, tx_id: " << id);
        tvc.m_verifivation_failed = true;
        return false;
    }
    //TODO: add rule for relay, based on tx size/fee ratio

    if(!check_inputs_types_supported(tx))
    {
        tvc.m_verifivation_failed = true;
        return false;
    }

    uint64_t inputs_amount = 0;
    if(!get_inputs_money_amount(tx, inputs_amount))
    {
        tvc.m_verifivation_failed = true;
        return false;
    }

    uint64_t outputs_amount = get_outs_money_amount(tx);

    if(outputs_amount >= inputs_amount)
    {
        LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount);
        tvc.m_verifivation_failed = true;
        return false;
    }

    //check key images for transaction if it is not kept by block
    if(!kept_by_block)
    {
        if(have_tx_keyimges_as_spent(tx))
        {
            LOG_ERROR("Transaction with id= "<< id << " used already spent key images");
            tvc.m_verifivation_failed = true;
            return false;
        }
    }


    crypto::hash max_used_block_id = null_hash;
    uint64_t max_used_block_height = 0;
    bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
    CRITICAL_REGION_LOCAL(m_transactions_lock);
    if(!ch_inp_res)
    {
        if(kept_by_block)
        {
            //anyway add this transaction to pool, because it related to block
            auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
            CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
            txd_p.first->second.blob_size = blob_size;
            txd_p.first->second.tx = tx;
            txd_p.first->second.fee = inputs_amount - outputs_amount;
            txd_p.first->second.max_used_block_id = null_hash;
            txd_p.first->second.max_used_block_height = 0;
            txd_p.first->second.kept_by_block = kept_by_block;
            txd_p.first->second.receive_time = time(nullptr);
            tvc.m_verifivation_impossible = true;
            tvc.m_added_to_pool = true;
        } else
        {
            LOG_PRINT_L0("tx used wrong inputs, rejected");
            tvc.m_verifivation_failed = true;
            return false;
        }
    } else
    {
        //update transactions container
        auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
        CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
        txd_p.first->second.blob_size = blob_size;
        txd_p.first->second.tx = tx;
        txd_p.first->second.kept_by_block = kept_by_block;
        txd_p.first->second.fee = inputs_amount - outputs_amount;
        txd_p.first->second.max_used_block_id = max_used_block_id;
        txd_p.first->second.max_used_block_height = max_used_block_height;
        txd_p.first->second.last_failed_height = 0;
        txd_p.first->second.last_failed_id = null_hash;
        txd_p.first->second.receive_time = time(nullptr);
        tvc.m_added_to_pool = true;

        if(txd_p.first->second.fee > 0)
            tvc.m_should_be_relayed = true;
    }

    tvc.m_verifivation_failed = true;
    //update image_keys container, here should everything goes ok.
    BOOST_FOREACH(const auto& in, tx.vin)
    {
        CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
        std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
        CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block
                             << ",  kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
                             << "tx_id=" << id );
        auto ins_res = kei_image_set.insert(id);
        CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
    }

    tvc.m_verifivation_failed = false;
    //succeed
    return true;
}
Exemplo n.º 3
0
	//---------------------------------------------------------------------------------
	bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, tx_verification_context& tvc, bool kept_by_block, std::string alias)
	{
		size_t blob_size = get_object_blobsize(tx);
		//#9Protection from big transaction flood
		if (!kept_by_block && blob_size > currency::get_max_transaction_blob_size(m_blockchain.get_current_blockchain_height()))
		{
			LOG_PRINT_L0("transaction is too big (" << blob_size << ")bytes for current transaction flow, tx_id: " << id);
			tvc.m_verifivation_failed = true;
			return false;
		}

		if (!check_inputs_types_supported(tx))
		{
			tvc.m_verifivation_failed = true;
			return false;
		}

		uint64_t inputs_amount = 0;
		if (!get_inputs_money_amount(tx, inputs_amount))
		{
			tvc.m_verifivation_failed = true;
			return false;
		}

		uint64_t outputs_amount = get_outs_money_amount(tx);

		if (outputs_amount >= inputs_amount)
		{
			LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount);
			tvc.m_verifivation_failed = true;
			return false;
		}

		//check key images for transaction if it is not kept by blockhave_tx_keyimges_as_spent
		if (!kept_by_block)
		{
			if (have_tx_keyimges_as_spent(tx))
			{
				LOG_ERROR("Transaction with id= " << id << " used already spent key images");
				tvc.m_verifivation_failed = true;
				return false;
			}

			//transaction spam protection, soft rule
			if (inputs_amount - outputs_amount < TX_POOL_MINIMUM_FEE)
			{
				LOG_ERROR("Transaction with id= " << id << " has too small fee: " << inputs_amount - outputs_amount << ", expected fee: " << DEFAULT_FEE);
				tvc.m_verifivation_failed = true;
				return false;
			}
		}

		crypto::hash max_used_block_id = null_hash;
		uint64_t max_used_block_height = 0;
		bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
		CRITICAL_REGION_LOCAL(m_transactions_lock);
		if (!ch_inp_res)
		{
			if (kept_by_block)
			{
				//if there is a same alias on the block, then delete the tx with the same alias in the pool
				crypto::hash hash;
				if (alias.size() && (hash = find_alias(alias)) != null_hash)
				{
					transaction tx = AUTO_VAL_INIT(tx);
					size_t size = 0;
					uint64_t  fee = 0;
					take_tx(hash, tx, size, fee);
					LOG_PRINT_L2("Found alias " << alias << " in block, delete pool tx with the same alias: " << id);
				}
				//anyway add this transaction to pool, because it related to block
				auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
				if (!txd_p.second)
				{
					return false;
				}

				//CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
				txd_p.first->second.blob_size = blob_size;
				txd_p.first->second.tx = tx;
				txd_p.first->second.fee = inputs_amount - outputs_amount;
				txd_p.first->second.max_used_block_id = null_hash;
				txd_p.first->second.max_used_block_height = 0;
				txd_p.first->second.kept_by_block = kept_by_block;
				txd_p.first->second.receive_time = time(nullptr);
				tvc.m_verifivation_impossible = true;
				tvc.m_added_to_pool = true;
			}
			else
			{
				LOG_PRINT_L0("tx used wrong inputs, rejected");
				tvc.m_verifivation_failed = true;
				return false;
			}
		}
		else
		{
			//check alias repeat or not
			if (!add_alias_tx_pair(alias, id))
			{
				tvc.m_verifivation_failed = true;
				tvc.m_added_to_pool = false;
				return false;
			}

			//update transactions container
			auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
			if (!txd_p.second)
			{
				return false;
			}

			//CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
			txd_p.first->second.blob_size = blob_size;
			txd_p.first->second.tx = tx;
			txd_p.first->second.kept_by_block = kept_by_block;
			txd_p.first->second.fee = inputs_amount - outputs_amount;
			txd_p.first->second.max_used_block_id = max_used_block_id;
			txd_p.first->second.max_used_block_height = max_used_block_height;
			txd_p.first->second.last_failed_height = 0;
			txd_p.first->second.last_failed_id = null_hash;
			txd_p.first->second.receive_time = time(nullptr);
			tvc.m_added_to_pool = true;

			if (txd_p.first->second.fee > 0)
				tvc.m_should_be_relayed = true;
		}

		tvc.m_verifivation_failed = true;
		//update image_keys container, here should everything goes ok.
		BOOST_FOREACH(const auto& in, tx.vin)
		{
			CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
			std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
			CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block
				<< ",  kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
				<< "tx_id=" << id);
			auto ins_res = kei_image_set.insert(id);
			CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
		}

		tvc.m_verifivation_failed = false;
		//succeed
		return true;
	}
Exemplo n.º 4
0
  //---------------------------------------------------------------------------------
  bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block)
  {


    if(!check_inputs_types_supported(tx))
    {
      tvc.m_verifivation_failed = true;
      return false;
    }

    uint64_t inputs_amount = 0;
    if(!get_inputs_money_amount(tx, inputs_amount))
    {
      tvc.m_verifivation_failed = true;
      return false;
    }

    uint64_t outputs_amount = get_outs_money_amount(tx);

    if(outputs_amount >= inputs_amount)
    {
      LOG_PRINT_L1("transaction use more money then it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
      tvc.m_verifivation_failed = true;
      return false;
    }

    uint64_t fee = inputs_amount - outputs_amount;
    uint64_t needed_fee = blob_size / 1024;
    needed_fee += (blob_size % 1024) ? 1 : 0;
    needed_fee *= FEE_PER_KB;
    if (!kept_by_block && fee < needed_fee /*&& fee < MINING_ALLOWED_LEGACY_FEE*/)
    {
      LOG_PRINT_L1("transaction fee is not enough: " << print_money(fee) << ", minumim fee: " << print_money(needed_fee));
      tvc.m_verifivation_failed = true;
      return false;
    }

    if (!kept_by_block && blob_size >= TRANSACTION_SIZE_LIMIT)
    {
      LOG_PRINT_L1("transaction is too big: " << blob_size << " bytes, maximum size: " << TRANSACTION_SIZE_LIMIT);
      tvc.m_verifivation_failed = true;
      return false;
    }

    //check key images for transaction if it is not kept by block
    if(!kept_by_block)
    {
      if(have_tx_keyimges_as_spent(tx))
      {
        LOG_PRINT_L1("Transaction with id= "<< id << " used already spent key images");
        tvc.m_verifivation_failed = true;
        return false;
      }
    }


    crypto::hash max_used_block_id = null_hash;
    uint64_t max_used_block_height = 0;
    bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
    CRITICAL_REGION_LOCAL(m_transactions_lock);
    if(!ch_inp_res)
    {
      if(kept_by_block)
      {
        //anyway add this transaction to pool, because it related to block
        auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
        CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
        txd_p.first->second.blob_size = blob_size;
        txd_p.first->second.tx = tx;
        txd_p.first->second.fee = inputs_amount - outputs_amount;
        txd_p.first->second.max_used_block_id = null_hash;
        txd_p.first->second.max_used_block_height = 0;
        txd_p.first->second.kept_by_block = kept_by_block;
        txd_p.first->second.receive_time = time(nullptr);
        tvc.m_verifivation_impossible = true;
        tvc.m_added_to_pool = true;
      }else
      {
        LOG_PRINT_L1("tx used wrong inputs, rejected");
        tvc.m_verifivation_failed = true;
        return false;
      }
    }else
    {
      //update transactions container
      auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
      CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
      txd_p.first->second.blob_size = blob_size;
      txd_p.first->second.tx = tx;
      txd_p.first->second.kept_by_block = kept_by_block;
      txd_p.first->second.fee = inputs_amount - outputs_amount;
      txd_p.first->second.max_used_block_id = max_used_block_id;
      txd_p.first->second.max_used_block_height = max_used_block_height;
      txd_p.first->second.last_failed_height = 0;
      txd_p.first->second.last_failed_id = null_hash;
      txd_p.first->second.receive_time = time(nullptr);
      tvc.m_added_to_pool = true;

      if(txd_p.first->second.fee > 0)
        tvc.m_should_be_relayed = true;
    }

    tvc.m_verifivation_failed = true;
    //update image_keys container, here should everything goes ok.
    BOOST_FOREACH(const auto& in, tx.vin)
    {
      CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
      std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
      CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block
                                          << ",  kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
                                          << "tx_id=" << id );
      auto ins_res = kei_image_set.insert(id);
      CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
    }

    tvc.m_verifivation_failed = false;

    m_txs_by_fee.emplace((double)blob_size / fee, id);
    //succeed
    return true;
  }