//----------------------------------------------------------------------------------------------- bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block) { tvc = boost::value_initialized<tx_verification_context>(); //want to process all transactions sequentially CRITICAL_REGION_LOCAL(m_incoming_tx_lock); if(tx_blob.size() > m_currency.maxTxSize()) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected"); tvc.m_verifivation_failed = true; return false; } crypto::hash tx_hash = null_hash; crypto::hash tx_prefixt_hash = null_hash; Transaction tx; if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to parse, rejected"); tvc.m_verifivation_failed = true; return false; } //std::cout << "!"<< tx.vin.size() << std::endl; if(!check_tx_syntax(tx)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected"); tvc.m_verifivation_failed = true; return false; } if(!check_tx_semantic(tx, keeped_by_block)) { LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected"); tvc.m_verifivation_failed = true; return false; } bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block); if(tvc.m_verifivation_failed) { if (!tvc.m_tx_fee_too_small) { LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash); } else { LOG_PRINT_L0("Transaction verification failed: " << tx_hash); } } else if(tvc.m_verifivation_impossible) { LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash); } if (tvc.m_added_to_pool) { LOG_PRINT_L1("tx added: " << tx_hash); poolUpdated(); } return r; }
//--------------------------------------------------------------- bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce) { CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max"); size_t start_pos = tx_extra.size(); tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size()); //write tag tx_extra[start_pos] = TX_EXTRA_NONCE; //write len ++start_pos; tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size()); //write data ++start_pos; memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size()); return true; }
//----------------------------------------------------------------------------------------------- bool core::handle_incoming_block_blob(const blobdata& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block) { if (block_blob.size() > m_currency.maxBlockBlobSize()) { LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected"); bvc.m_verifivation_failed = true; return false; } Block b = AUTO_VAL_INIT(b); if (!parse_and_validate_block_from_blob(block_blob, b)) { LOG_PRINT_L0("Failed to parse and validate new block"); bvc.m_verifivation_failed = true; return false; } return handle_incoming_block(b, bvc, control_miner, relay_block); }
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id) { if (sizeof(crypto::hash) + 1 != extra_nonce.size()) return false; if (TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0]) return false; payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1); return true; }
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce) { if (extra_nonce.size() > TX_EXTRA_NONCE_MAX_COUNT) { return false; } size_t start_pos = tx_extra.size(); tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size()); //write tag tx_extra[start_pos] = TX_EXTRA_NONCE; //write len ++start_pos; tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size()); //write data ++start_pos; memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size()); return true; }
//--------------------------------------------------------------- bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash) { std::stringstream ss; ss << tx_blob; binary_archive<false> ba(ss); bool r = ::serialization::serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); //TODO: validate tx crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash); get_transaction_prefix_hash(tx, tx_prefix_hash); return true; }
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, Transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash) { std::stringstream ss; ss << tx_blob; binary_archive<false> ba(ss); bool r = ::serialization::serialize(ba, tx); if (!r) { return false; } //TODO: validate tx crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash); get_transaction_prefix_hash(tx, tx_prefix_hash); return true; }
//--------------------------------------------------------------- bool construct_miner_tx(uint64_t height, uint64_t already_generated_coins, const account_public_address& miner_address, transaction& tx, uint64_t fee, std::vector<size_t>& blocks_sizes, size_t current_block_size, const blobdata& extra_nonce, size_t max_outs) { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); if(extra_nonce.size()) if(!add_tx_extra_nonce(tx, extra_nonce)) return false; txin_gen in; in.height = height; bool block_too_big = false; uint64_t block_reward = get_block_reward(blocks_sizes, current_block_size, block_too_big, already_generated_coins) + fee; if(block_too_big) { LOG_PRINT_L0("Block is too big"); return false; } std::vector<size_t> out_amounts; decompose_amount_into_digits(block_reward, DEFAULT_FEE, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); while (max_outs < out_amounts.size()) { out_amounts[out_amounts.size() - 2] += out_amounts.back(); out_amounts.resize(out_amounts.size() - 1); } size_t summary_amounts = 0; for (size_t no = 0; no < out_amounts.size(); no++) { crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);; crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")"); r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")"); txout_to_key tk; tk.key = out_eph_public_key; tx_out out; summary_amounts += out.amount = out_amounts[no]; out.target = tk; tx.vout.push_back(out); } CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward); tx.version = CURRENT_TRANSACTION_VERSION; //lock tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.vin.push_back(in); //LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee) // << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2); return true; }
//--------------------------------------------------------------- void get_blob_hash(const blobdata& blob, crypto::hash& res) { cn_fast_hash(blob.data(), blob.size(), res); }