Esempio n. 1
0
  //-----------------------------------------------------------------------------------------------
  bool core::check_tx_semantic(const Transaction& tx, bool keeped_by_block)
  {
    if(!tx.vin.size())
    {
      LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx));
      return false;
    }

    if(!check_inputs_types_supported(tx))
    {
      LOG_PRINT_RED_L0("unsupported input types for tx id= " << get_transaction_hash(tx));
      return false;
    }

    if(!check_outs_valid(tx))
    {
      LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
      return false;
    }

    if(!check_money_overflow(tx))
    {
      LOG_PRINT_RED_L0("tx have money overflow, rejected for tx id= " << get_transaction_hash(tx));
      return false;
    }

    uint64_t amount_in = m_currency.getTransactionAllInputsAmount(tx);
    uint64_t amount_out = get_outs_money_amount(tx);

    if(amount_in <= amount_out)
    {
      LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx));
      return false;
    }

    if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - m_currency.minerTxBlobReservedSize())
    {
      LOG_PRINT_RED_L0("transaction is too big " << get_object_blobsize(tx) << ", maximum allowed size is " <<
        (m_blockchain_storage.get_current_comulative_blocksize_limit() - m_currency.minerTxBlobReservedSize()));
      return false;
    }

    //check if tx use different key images
    if(!check_tx_inputs_keyimages_diff(tx))
    {
      LOG_PRINT_RED_L0("tx has a few inputs with identical keyimages");
      return false;
    }

    if (!checkMultisignatureInputsDiff(tx)) {
      LOG_PRINT_RED_L0("tx has a few multisignature inputs with identical output indexes");
      return false;
    }

    return true;
  }
Esempio n. 2
0
  //------------------------------------------------------------------------------------------------------------------------------
  bool wallet_rpc_server::on_clonetelepod(const wallet_rpc::COMMAND_RPC_CLONETELEPOD::request& req, wallet_rpc::COMMAND_RPC_CLONETELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx)
  {
    currency::transaction tx2 = AUTO_VAL_INIT(tx2);
    //new destination account 
    currency::account_base acc2 = AUTO_VAL_INIT(acc2);
    acc2.generate();

    if (!build_transaction_from_telepod(req.tpd, acc2.get_keys().m_account_address, tx2, res.status))
    {
      LOG_ERROR("Failed to build_transaction_from_telepod(...)");
      return true;
    }

    //send transaction to daemon
    currency::COMMAND_RPC_SEND_RAW_TX::request req_send_raw;
    req_send_raw.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx2));
    currency::COMMAND_RPC_SEND_RAW_TX::response rsp_send_raw;
    bool r = m_wallet.get_core_proxy()->call_COMMAND_RPC_SEND_RAW_TX(req_send_raw, rsp_send_raw);
    if (!r || rsp_send_raw.status != CORE_RPC_STATUS_OK)
    {
      LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
      res.status = "INTERNAL_ERROR";
      return true;
    }

    res.tpd.basement_tx_id_hex = string_tools::pod_to_hex(currency::get_transaction_hash(tx2));
    std::string acc2_buff = epee::serialization::store_t_to_binary(acc2);
    res.tpd.account_keys_hex = string_tools::buff_to_hex_nodelimer(acc2_buff);

    res.status = "OK";
    LOG_PRINT_GREEN("TELEPOD ISSUED [" << currency::print_money(currency::get_outs_money_amount(tx2)) << "BBR, base_tx_id: ]" << currency::get_transaction_hash(tx2), LOG_LEVEL_0);

    return true;
  }
Esempio n. 3
0
//---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block)
{
    crypto::hash h = null_hash;
    size_t blob_size = get_object_blobsize(tx);
    get_transaction_hash(tx, h);
    return add_tx(tx, h, blob_size, tvc, keeped_by_block);
}
Esempio n. 4
0
  //------------------------------------------------------------------------------------------------------------------------------
  bool wallet_rpc_server::on_withdrawtelepod(const wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::request& req, wallet_rpc::COMMAND_RPC_WITHDRAWTELEPOD::response& res, epee::json_rpc::error& er, connection_context& cntx)
  {
    currency::transaction tx2 = AUTO_VAL_INIT(tx2);
    //parse destination add 
    currency::account_public_address acc_addr = AUTO_VAL_INIT(acc_addr);
    if (!currency::get_account_address_from_str(acc_addr, req.addr))
    {
      LOG_ERROR("Failed to build_transaction_from_telepod(...)");
      res.status = "BAD_ADDRESS";
      return true;
    }


    if (!build_transaction_from_telepod(req.tpd, acc_addr, tx2, res.status))
    {
      LOG_ERROR("Failed to build_transaction_from_telepod(...)");
      return true;
    }

    //send transaction to daemon
    currency::COMMAND_RPC_SEND_RAW_TX::request req_send_raw;
    req_send_raw.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx2));
    currency::COMMAND_RPC_SEND_RAW_TX::response rsp_send_raw;
    bool r = m_wallet.get_core_proxy()->call_COMMAND_RPC_SEND_RAW_TX(req_send_raw, rsp_send_raw);
    if (!r || rsp_send_raw.status != CORE_RPC_STATUS_OK)
    {
      LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
      res.status = "INTERNAL_ERROR";
      return true;
    }

    res.status = "OK";
    LOG_PRINT_GREEN("TELEPOD WITHDRAWN [" << currency::print_money(currency::get_outs_money_amount(tx2)) << "BBR, tx_id: ]" << currency::get_transaction_hash(tx2), LOG_LEVEL_0);

    return true;
  }
Esempio n. 5
0
  //------------------------------------------------------------------------------------------------------------------------------
  bool wallet_rpc_server::build_transaction_from_telepod(const wallet_rpc::telepod& tlp, const currency::account_public_address& acc2, currency::transaction& tx2, std::string& status)
  {
    //check if base transaction confirmed
    currency::COMMAND_RPC_GET_TRANSACTIONS::request get_tx_req = AUTO_VAL_INIT(get_tx_req);
    currency::COMMAND_RPC_GET_TRANSACTIONS::response get_tx_rsp = AUTO_VAL_INIT(get_tx_rsp);
    get_tx_req.txs_hashes.push_back(tlp.basement_tx_id_hex);
    if (!m_wallet.get_core_proxy()->call_COMMAND_RPC_GET_TRANSACTIONS(get_tx_req, get_tx_rsp)
      || get_tx_rsp.status != CORE_RPC_STATUS_OK
      || !get_tx_rsp.txs_as_hex.size())
    {
      status = "UNCONFIRMED";
      return false;
    }

    //extract account keys
    std::string acc_buff;
    currency::account_base acc = AUTO_VAL_INIT(acc);
    if (!string_tools::parse_hexstr_to_binbuff(tlp.account_keys_hex, acc_buff))
    {
      LOG_ERROR("Failed to parse_hexstr_to_binbuff(tlp.account_keys_hex, acc_buff)");
      status = "BAD";
      return false;
    }
    if (!epee::serialization::load_t_from_binary(acc, acc_buff))
    {
      LOG_ERROR("Failed to load_t_from_binary(acc, acc_buff)");
      status = "BAD";
      return false;
    }

    //extract transaction
    currency::transaction tx = AUTO_VAL_INIT(tx);
    std::string buff;
    if (!string_tools::parse_hexstr_to_binbuff(get_tx_rsp.txs_as_hex.back(), buff))
    {
      LOG_ERROR("Failed to parse_hexstr_to_binbuff(get_tx_rsp.txs_as_hex.back(), buff)");
      status = "INTERNAL_ERROR";
      return false;
    }
    if (!currency::parse_and_validate_tx_from_blob(buff, tx))
    {
      LOG_ERROR("Failed to currency::parse_and_validate_tx_from_blob(buff, tx)");
      status = "INTERNAL_ERROR";
      return false;
    }

    crypto::public_key tx_pub_key = currency::get_tx_pub_key_from_extra(tx);
    if (tx_pub_key == currency::null_pkey)
    {
      LOG_ERROR("Failed to currency::get_tx_pub_key_from_extra(tx)");
      status = "BAD";
      return false;

    }

    //get transaction global output indices 
    currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request get_ind_req = AUTO_VAL_INIT(get_ind_req);
    currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response get_ind_rsp = AUTO_VAL_INIT(get_ind_rsp);
    get_ind_req.txid = currency::get_transaction_hash(tx);
    if (!m_wallet.get_core_proxy()->call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(get_ind_req, get_ind_rsp)
      || get_ind_rsp.status != CORE_RPC_STATUS_OK
      || get_ind_rsp.o_indexes.size() != tx.vout.size())
    {
      LOG_ERROR("Problem with call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(....) ");
      status = "INTERNAL_ERROR";
      return false;
    }

    //prepare inputs
    std::vector<currency::tx_source_entry> sources;
    size_t i = 0;
    uint64_t amount = 0;
    for (auto& o : get_ind_rsp.o_indexes)
    {
      //check if input is for telepod's address
      if (currency::is_out_to_acc(acc.get_keys(), boost::get<currency::txout_to_key>(tx.vout[i].target), tx_pub_key, i))
      {
        //income output 
        amount += tx.vout[i].amount;
        sources.resize(sources.size() + 1);
        currency::tx_source_entry& tse = sources.back();
        tse.amount = tx.vout[i].amount;
        tse.outputs.push_back(currency::tx_source_entry::output_entry(o, boost::get<currency::txout_to_key>(tx.vout[i].target).key));
        tse.real_out_tx_key = tx_pub_key;
        tse.real_output = 0;
        tse.real_output_in_tx_index = i;
      }
      ++i;
    }


    //prepare outputs
    std::vector<currency::tx_destination_entry> dsts(1);
    currency::tx_destination_entry& dst = dsts.back();
    dst.addr = acc2;
    dst.amount = amount - DEFAULT_FEE;

    //generate transaction
    const std::vector<uint8_t> extra;
    bool r = currency::construct_tx(acc.get_keys(), sources, dsts, extra, tx2, 0);
    if (!r)
    {
      LOG_ERROR("Problem with construct_tx(....) ");
      status = "INTERNAL_ERROR";
      return false;
    }
    if (CURRENCY_MAX_TRANSACTION_BLOB_SIZE <= get_object_blobsize(tx2))
    {
      LOG_ERROR("Problem with construct_tx(....), blobl size os too big: " << get_object_blobsize(tx2));
      status = "INTERNAL_ERROR";
      return false;
    }

    return true;
  }
Esempio n. 6
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;
	}