bool Currency::constructMinerTx(uint32_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize, uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx, const BinaryArray& extraNonce/* = BinaryArray()*/, size_t maxOuts/* = 1*/) const { tx.inputs.clear(); tx.outputs.clear(); tx.extra.clear(); KeyPair txkey = generateKeyPair(); addTransactionPublicKeyToExtra(tx.extra, txkey.publicKey); if (!extraNonce.empty()) { if (!addExtraNonceToTransactionExtra(tx.extra, extraNonce)) { return false; } } BaseInput in; in.blockIndex = height; uint64_t blockReward; int64_t emissionChange; if (!getBlockReward(medianSize, currentBlockSize, alreadyGeneratedCoins, fee, height, blockReward, emissionChange)) { logger(INFO) << "Block is too big"; return false; } std::vector<uint64_t> outAmounts; decompose_amount_into_digits(blockReward, m_defaultDustThreshold, [&outAmounts](uint64_t a_chunk) { outAmounts.push_back(a_chunk); }, [&outAmounts](uint64_t a_dust) { outAmounts.push_back(a_dust); }); if (!(1 <= maxOuts)) { logger(ERROR, BRIGHT_RED) << "max_out must be non-zero"; return false; } while (maxOuts < outAmounts.size()) { outAmounts[outAmounts.size() - 2] += outAmounts.back(); outAmounts.resize(outAmounts.size() - 1); } uint64_t summaryAmounts = 0; for (size_t no = 0; no < outAmounts.size(); no++) { Crypto::KeyDerivation derivation = boost::value_initialized<Crypto::KeyDerivation>(); Crypto::PublicKey outEphemeralPubKey = boost::value_initialized<Crypto::PublicKey>(); bool r = Crypto::generate_key_derivation(minerAddress.viewPublicKey, txkey.secretKey, derivation); if (!(r)) { logger(ERROR, BRIGHT_RED) << "while creating outs: failed to generate_key_derivation(" << minerAddress.viewPublicKey << ", " << txkey.secretKey << ")"; return false; } r = Crypto::derive_public_key(derivation, no, minerAddress.spendPublicKey, outEphemeralPubKey); if (!(r)) { logger(ERROR, BRIGHT_RED) << "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", " << minerAddress.spendPublicKey << ")"; return false; } KeyOutput tk; tk.key = outEphemeralPubKey; TransactionOutput out; summaryAmounts += out.amount = outAmounts[no]; out.target = tk; tx.outputs.push_back(out); } if (!(summaryAmounts == blockReward)) { logger(ERROR, BRIGHT_RED) << "Failed to construct miner tx, summaryAmounts = " << summaryAmounts << " not equal blockReward = " << blockReward; return false; } tx.version = TRANSACTION_VERSION_1; //lock tx.unlockTime = height + m_minedMoneyUnlockWindow; tx.inputs.push_back(in); return true; }
bool Currency::constructMinerTx(size_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize, uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx, const blobdata& extraNonce/* = blobdata()*/, size_t maxOuts/* = 1*/) const { tx.vin.clear(); tx.vout.clear(); tx.extra.clear(); KeyPair txkey = KeyPair::generate(); add_tx_pub_key_to_extra(tx, txkey.pub); if (!extraNonce.empty()) { if (!add_extra_nonce_to_tx_extra(tx.extra, extraNonce)) { return false; } } TransactionInputGenerate in; in.height = height; uint64_t blockReward; int64_t emissionChange; if (!getBlockReward(medianSize, currentBlockSize, alreadyGeneratedCoins, fee, blockReward, emissionChange)) { LOG_PRINT_L0("Block is too big"); return false; } #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) LOG_PRINT_L1("Creating block template: reward " << blockReward << ", fee " << fee); #endif std::vector<uint64_t> outAmounts; decompose_amount_into_digits(blockReward, m_defaultDustThreshold, [&outAmounts](uint64_t a_chunk) { outAmounts.push_back(a_chunk); }, [&outAmounts](uint64_t a_dust) { outAmounts.push_back(a_dust); }); CHECK_AND_ASSERT_MES(1 <= maxOuts, false, "max_out must be non-zero"); while (maxOuts < outAmounts.size()) { outAmounts[outAmounts.size() - 2] += outAmounts.back(); outAmounts.resize(outAmounts.size() - 1); } uint64_t summaryAmounts = 0; for (size_t no = 0; no < outAmounts.size(); no++) { crypto::key_derivation derivation = boost::value_initialized<crypto::key_derivation>(); crypto::public_key outEphemeralPubKey = boost::value_initialized<crypto::public_key>(); bool r = crypto::generate_key_derivation(minerAddress.m_viewPublicKey, txkey.sec, derivation); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << minerAddress.m_viewPublicKey << ", " << txkey.sec << ")"); r = crypto::derive_public_key(derivation, no, minerAddress.m_spendPublicKey, outEphemeralPubKey); CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< minerAddress.m_spendPublicKey << ")"); TransactionOutputToKey tk; tk.key = outEphemeralPubKey; TransactionOutput out; summaryAmounts += out.amount = outAmounts[no]; out.target = tk; tx.vout.push_back(out); } CHECK_AND_ASSERT_MES(summaryAmounts == blockReward, false, "Failed to construct miner tx, summaryAmounts = " << summaryAmounts << " not equal blockReward = " << blockReward); tx.version = CURRENT_TRANSACTION_VERSION; //lock tx.unlockTime = height + m_minedMoneyUnlockWindow; tx.vin.push_back(in); return true; }