ostream& operator<<(ostream& os, const transfer_details& td) { os << "Block: " << td.m_block_height << " time: " << timestamp_to_str(td.m_block_timestamp) << " tx hash: " << td.tx_hash() << " out idx: " << td.m_internal_output_index << " amount: " << print_money(td.amount()); return os; }
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) { // TODO; std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx)); uint64_t amount = in_tx.vout[out_index].amount; LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { m_listener->moneySpent(tx_hash, amount); } }
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) { std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx)); uint64_t amount = tx.vout[out_index].amount; LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height << ", tx: " << tx_hash << ", amount: " << print_money(amount)); if (m_listener) { m_listener->moneyReceived(tx_hash, amount); } }
//--------------------------------------------------------------------------------- std::string tx_memory_pool::print_pool(bool short_format) const { std::stringstream ss; CRITICAL_REGION_LOCAL(m_transactions_lock); for (const transactions_container::value_type& txe : m_transactions) { const tx_details& txd = txe.second; ss << "id: " << txe.first << std::endl; if (!short_format) { ss << obj_to_json_str(*const_cast<transaction*>(&txd.tx)) << std::endl; } ss << "blob_size: " << txd.blob_size << std::endl << "fee: " << print_money(txd.fee) << std::endl << "kept_by_block: " << (txd.kept_by_block ? 'T' : 'F') << std::endl << "max_used_block_height: " << txd.max_used_block_height << std::endl << "max_used_block_id: " << txd.max_used_block_id << std::endl << "last_failed_height: " << txd.last_failed_height << std::endl << "last_failed_id: " << txd.last_failed_id << std::endl; } return ss.str(); }
void print_player_info(bool pp) { TTF_Init(); SDL_Surface *message; message=SDL_LoadBMP("clear_player_info.bmp"); apply_surface(0,0,message,screen); SDL_Color color1={0,900,0}; font=TTF_OpenFont("font2.ttf",50); message=TTF_RenderText_Solid(font,"Player 1",color1); apply_surface(0,0,message,screen); if(pp==true) load_save_player1("player1"); color1={174,0,0}; message=TTF_RenderText_Solid(font,"Experience: ",color1); apply_surface(230,0,message,screen); print_xp(player1_xp,0,13); color1={255,194,0}; message=TTF_RenderText_Solid(font,"Money: ",color1); apply_surface(750,0,message,screen); print_money(player1_money,0,24); SDL_Flip(screen); }
//--------------------------------------------------------------------------------- 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; }
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count) { clearStatus(); vector<cryptonote::tx_destination_entry> dsts; cryptonote::tx_destination_entry de; // indicates if dst_addr is integrated address (address + payment_id) bool has_payment_id; crypto::hash8 payment_id_short; // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIXIN; PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 m_status = Status_Error; m_errorString = "Invalid destination address"; break; } std::vector<uint8_t> extra; // if dst_addr is not an integrated address, parse payment_id if (!has_payment_id && !payment_id.empty()) { // copy-pasted from simplewallet.cpp:2212 crypto::hash payment_id_long; bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long); if (r) { std::string extra_nonce; cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long); r = add_extra_nonce_to_tx_extra(extra, extra_nonce); } else { r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short); if (r) { std::string extra_nonce; set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short); r = add_extra_nonce_to_tx_extra(extra, extra_nonce); } } if (!r) { m_status = Status_Error; m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id; break; } } de.amount = amount; if (de.amount <= 0) { m_status = Status_Error; m_errorString = "Invalid amount"; break; } dsts.push_back(de); //std::vector<tools::wallet2::pending_tx> ptx_vector; try { transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? m_errorString = tr("daemon is busy. Please try again later."); m_status = Status_Error; } catch (const tools::error::no_connection_to_daemon&) { m_errorString = tr("no connection to daemon. Please make sure daemon is running."); m_status = Status_Error; } catch (const tools::error::wallet_rpc_error& e) { m_errorString = tr("RPC error: ") + e.to_string(); m_status = Status_Error; } catch (const tools::error::get_random_outs_error&) { m_errorString = tr("failed to get random outputs to mix"); m_status = Status_Error; } catch (const tools::error::not_enough_money& e) { m_status = Status_Error; std::ostringstream writer; writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % print_money(e.fee()); m_errorString = writer.str(); } catch (const tools::error::not_enough_outs_to_mix& e) { std::ostringstream writer; writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); } m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_not_constructed&) { m_errorString = tr("transaction was not constructed"); m_status = Status_Error; } catch (const tools::error::tx_rejected& e) { std::ostringstream writer; writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_sum_overflow& e) { m_errorString = e.what(); m_status = Status_Error; } catch (const tools::error::zero_destination&) { m_errorString = tr("one of destinations is zero"); m_status = Status_Error; } catch (const tools::error::tx_too_big& e) { m_errorString = tr("failed to find a suitable way to split transactions"); m_status = Status_Error; } catch (const tools::error::transfer_error& e) { m_errorString = string(tr("unknown transfer error: ")) + e.what(); m_status = Status_Error; } catch (const tools::error::wallet_internal_error& e) { m_errorString = string(tr("internal error: ")) + e.what(); m_status = Status_Error; } catch (const std::exception& e) { m_errorString = string(tr("unexpected error: ")) + e.what(); m_status = Status_Error; } catch (...) { m_errorString = tr("unknown error"); m_status = Status_Error; } } while (false); transaction->m_status = m_status; transaction->m_errorString = m_errorString; return transaction; }