bool get_aux_block_header_hash(const Block& b, Hash& res) { BinaryArray blob; if (!get_block_hashing_blob(b, blob)) { return false; } return getObjectHash(blob, res); }
bool parseAndValidateTransactionFromBinaryArray(const BinaryArray& tx_blob, Transaction& tx, Hash& tx_hash, Hash& tx_prefix_hash) { if (!fromBinaryArray(tx, tx_blob)) { return false; } //TODO: validate tx cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash); getObjectHash(*static_cast<TransactionPrefix*>(&tx), tx_prefix_hash); return true; }
Hash get_tx_tree_hash(const Block& b) { std::vector<Hash> txs_ids; Hash h = NULL_HASH; getObjectHash(b.baseTransaction, h); txs_ids.push_back(h); for (auto& th : b.transactionHashes) { txs_ids.push_back(th); } return get_tx_tree_hash(txs_ids); }
bool ICoreStub::getPoolChangesLite(const Crypto::Hash& tailBlockId, const std::vector<Crypto::Hash>& knownTxsIds, std::vector<CryptoNote::TransactionPrefixInfo>& addedTxs, std::vector<Crypto::Hash>& deletedTxsIds) { std::vector<CryptoNote::Transaction> added; bool returnStatus = getPoolChanges(tailBlockId, knownTxsIds, added, deletedTxsIds); for (const auto& tx : added) { CryptoNote::TransactionPrefixInfo tpi; tpi.txPrefix = tx; tpi.txHash = getObjectHash(tx); addedTxs.push_back(std::move(tpi)); } return returnStatus; }
size_t ICoreStub::addChain(const std::vector<const CryptoNote::IBlock*>& chain) { size_t blocksCounter = 0; for (const CryptoNote::IBlock* block : chain) { for (size_t txNumber = 0; txNumber < block->getTransactionCount(); ++txNumber) { const CryptoNote::Transaction& tx = block->getTransaction(txNumber); Crypto::Hash txHash = CryptoNote::NULL_HASH; size_t blobSize = 0; getObjectHash(tx, txHash, blobSize); addTransaction(tx); } addBlock(block->getBlock()); ++blocksCounter; } return blocksCounter; }
bool get_block_hash(const Block& b, Hash& res) { BinaryArray ba; if (!get_block_hashing_blob(b, ba)) { return false; } // The header of block version 1 differs from headers of blocks starting from v.2 if (BLOCK_MAJOR_VERSION_2 == b.majorVersion || BLOCK_MAJOR_VERSION_3 == b.majorVersion) { BinaryArray parent_blob; auto serializer = makeParentBlockSerializer(b, true, false); if (!toBinaryArray(serializer, parent_blob)) return false; ba.insert(ba.end(), parent_blob.begin(), parent_blob.end()); } return getObjectHash(ba, res); }
void WalletUnconfirmedTransactions::add(const Transaction& tx, TransactionId transactionId, uint64_t amount, const std::list<TransactionOutputInformation>& usedOutputs) { UnconfirmedTransferDetails& utd = m_unconfirmedTxs[getObjectHash(tx)]; utd.amount = amount; utd.sentTime = time(nullptr); utd.tx = tx; utd.transactionId = transactionId; uint64_t outsAmount = 0; // process used outputs utd.usedOutputs.reserve(usedOutputs.size()); for (const auto& out : usedOutputs) { auto id = getOutputId(out); utd.usedOutputs.push_back(id); m_usedOutputs.insert(id); outsAmount += out.amount; } utd.outsAmount = outsAmount; }
bool constructTransaction( const AccountKeys& sender_account_keys, const std::vector<TransactionSourceEntry>& sources, const std::vector<TransactionDestinationEntry>& destinations, std::vector<uint8_t> extra, Transaction& tx, uint64_t unlock_time, Logging::ILogger& log) { LoggerRef logger(log, "construct_tx"); tx.inputs.clear(); tx.outputs.clear(); tx.signatures.clear(); tx.version = CURRENT_TRANSACTION_VERSION; tx.unlockTime = unlock_time; tx.extra = extra; KeyPair txkey = generateKeyPair(); addTransactionPublicKeyToExtra(tx.extra, txkey.publicKey); struct input_generation_context_data { KeyPair in_ephemeral; }; std::vector<input_generation_context_data> in_contexts; uint64_t summary_inputs_money = 0; //fill inputs for (const TransactionSourceEntry& src_entr : sources) { if (src_entr.realOutput >= src_entr.outputs.size()) { logger(ERROR) << "real_output index (" << src_entr.realOutput << ")bigger than output_keys.size()=" << src_entr.outputs.size(); return false; } summary_inputs_money += src_entr.amount; //KeyDerivation recv_derivation; in_contexts.push_back(input_generation_context_data()); KeyPair& in_ephemeral = in_contexts.back().in_ephemeral; KeyImage img; if (!generate_key_image_helper(sender_account_keys, src_entr.realTransactionPublicKey, src_entr.realOutputIndexInTransaction, in_ephemeral, img)) return false; //check that derived key is equal with real output key if (!(in_ephemeral.publicKey == src_entr.outputs[src_entr.realOutput].second)) { logger(ERROR) << "derived public key mismatch with output public key! " << ENDL << "derived_key:" << Common::podToHex(in_ephemeral.publicKey) << ENDL << "real output_public_key:" << Common::podToHex(src_entr.outputs[src_entr.realOutput].second); return false; } //put key image into tx input KeyInput input_to_key; input_to_key.amount = src_entr.amount; input_to_key.keyImage = img; //fill outputs array and use relative offsets for (const TransactionSourceEntry::OutputEntry& out_entry : src_entr.outputs) { input_to_key.outputIndexes.push_back(out_entry.first); } input_to_key.outputIndexes = absolute_output_offsets_to_relative(input_to_key.outputIndexes); tx.inputs.push_back(input_to_key); } // "Shuffle" outs std::vector<TransactionDestinationEntry> shuffled_dsts(destinations); std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const TransactionDestinationEntry& de1, const TransactionDestinationEntry& de2) { return de1.amount < de2.amount; }); uint64_t summary_outs_money = 0; //fill outputs size_t output_index = 0; for (const TransactionDestinationEntry& dst_entr : shuffled_dsts) { if (!(dst_entr.amount > 0)) { logger(ERROR, BRIGHT_RED) << "Destination with wrong amount: " << dst_entr.amount; return false; } KeyDerivation derivation; PublicKey out_eph_public_key; bool r = generate_key_derivation(dst_entr.addr.viewPublicKey, txkey.secretKey, derivation); if (!(r)) { logger(ERROR, BRIGHT_RED) << "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.viewPublicKey << ", " << txkey.secretKey << ")"; return false; } r = derive_public_key(derivation, output_index, dst_entr.addr.spendPublicKey, out_eph_public_key); if (!(r)) { logger(ERROR, BRIGHT_RED) << "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", " << dst_entr.addr.spendPublicKey << ")"; return false; } TransactionOutput out; out.amount = dst_entr.amount; KeyOutput tk; tk.key = out_eph_public_key; out.target = tk; tx.outputs.push_back(out); output_index++; summary_outs_money += dst_entr.amount; } //check money if (summary_outs_money > summary_inputs_money) { logger(ERROR) << "Transaction inputs money (" << summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")"; return false; } //generate ring signatures Hash tx_prefix_hash; getObjectHash(*static_cast<TransactionPrefix*>(&tx), tx_prefix_hash); size_t i = 0; for (const TransactionSourceEntry& src_entr : sources) { std::vector<const PublicKey*> keys_ptrs; for (const TransactionSourceEntry::OutputEntry& o : src_entr.outputs) { keys_ptrs.push_back(&o.second); } tx.signatures.push_back(std::vector<Signature>()); std::vector<Signature>& sigs = tx.signatures.back(); sigs.resize(src_entr.outputs.size()); generate_ring_signature(tx_prefix_hash, boost::get<KeyInput>(tx.inputs[i]).keyImage, keys_ptrs, in_contexts[i].in_ephemeral.secretKey, src_entr.realOutput, sigs.data()); i++; } return true; }
Hash TransactionPrefixImpl::getTransactionPrefixHash() const { return getObjectHash(m_txPrefix); }
std::unique_ptr<ITransactionReader> createTransactionPrefix(const Transaction& fullTransaction) { return std::unique_ptr<ITransactionReader> (new TransactionPrefixImpl(fullTransaction, getObjectHash(fullTransaction))); }
//----------------------------------------------------------------------- bool operator ==(const CryptoNote::Transaction& a, const CryptoNote::Transaction& b) { return getObjectHash(a) == getObjectHash(b); }
bool BlockchainExplorerDataBuilder::fillTransactionDetails(const Transaction& transaction, TransactionDetails& transactionDetails, uint64_t timestamp) { Crypto::Hash hash = getObjectHash(transaction); transactionDetails.hash = hash; transactionDetails.timestamp = timestamp; Crypto::Hash blockHash; uint32_t blockHeight; if (!core.getBlockContainingTx(hash, blockHash, blockHeight)) { transactionDetails.inBlockchain = false; transactionDetails.blockHeight = boost::value_initialized<uint32_t>(); transactionDetails.blockHash = boost::value_initialized<Crypto::Hash>(); } else { transactionDetails.inBlockchain = true; transactionDetails.blockHeight = blockHeight; transactionDetails.blockHash = blockHash; if (timestamp == 0) { Block block; if (!core.getBlockByHash(blockHash, block)) { return false; } transactionDetails.timestamp = block.timestamp; } } transactionDetails.size = getObjectBinarySize(transaction); transactionDetails.unlockTime = transaction.unlockTime; transactionDetails.totalOutputsAmount = get_outs_money_amount(transaction); uint64_t inputsAmount; if (!get_inputs_money_amount(transaction, inputsAmount)) { return false; } transactionDetails.totalInputsAmount = inputsAmount; if (transaction.inputs.size() > 0 && transaction.inputs.front().type() == typeid(BaseInput)) { //It's gen transaction transactionDetails.fee = 0; transactionDetails.mixin = 0; } else { uint64_t fee; if (!get_tx_fee(transaction, fee)) { return false; } transactionDetails.fee = fee; uint64_t mixin; if (!getMixin(transaction, mixin)) { return false; } transactionDetails.mixin = mixin; } Crypto::Hash paymentId; if (getPaymentId(transaction, paymentId)) { transactionDetails.paymentId = paymentId; } else { transactionDetails.paymentId = boost::value_initialized<Crypto::Hash>(); } fillTxExtra(transaction.extra, transactionDetails.extra); transactionDetails.signatures.reserve(transaction.signatures.size()); for (const std::vector<Crypto::Signature>& signatures : transaction.signatures) { std::vector<Crypto::Signature> signaturesDetails; signaturesDetails.reserve(signatures.size()); for (const Crypto::Signature& signature : signatures) { signaturesDetails.push_back(std::move(signature)); } transactionDetails.signatures.push_back(std::move(signaturesDetails)); } transactionDetails.inputs.reserve(transaction.inputs.size()); for (const TransactionInput& txIn : transaction.inputs) { TransactionInputDetails txInDetails; if (txIn.type() == typeid(BaseInput)) { TransactionInputGenerateDetails txInGenDetails; txInGenDetails.height = boost::get<BaseInput>(txIn).blockIndex; txInDetails.amount = 0; for (const TransactionOutput& out : transaction.outputs) { txInDetails.amount += out.amount; } txInDetails.input = txInGenDetails; } else if (txIn.type() == typeid(KeyInput)) { TransactionInputToKeyDetails txInToKeyDetails; const KeyInput& txInToKey = boost::get<KeyInput>(txIn); std::list<std::pair<Crypto::Hash, size_t>> outputReferences; if (!core.scanOutputkeysForIndices(txInToKey, outputReferences)) { return false; } txInDetails.amount = txInToKey.amount; txInToKeyDetails.outputIndexes = txInToKey.outputIndexes; txInToKeyDetails.keyImage = txInToKey.keyImage; txInToKeyDetails.mixin = txInToKey.outputIndexes.size(); txInToKeyDetails.output.number = outputReferences.back().second; txInToKeyDetails.output.transactionHash = outputReferences.back().first; txInDetails.input = txInToKeyDetails; } else if (txIn.type() == typeid(MultisignatureInput)) { TransactionInputMultisignatureDetails txInMultisigDetails; const MultisignatureInput& txInMultisig = boost::get<MultisignatureInput>(txIn); txInDetails.amount = txInMultisig.amount; txInMultisigDetails.signatures = txInMultisig.signatureCount; std::pair<Crypto::Hash, size_t> outputReference; if (!core.getMultisigOutputReference(txInMultisig, outputReference)) { return false; } txInMultisigDetails.output.number = outputReference.second; txInMultisigDetails.output.transactionHash = outputReference.first; txInDetails.input = txInMultisigDetails; } else { return false; } transactionDetails.inputs.push_back(std::move(txInDetails)); } transactionDetails.outputs.reserve(transaction.outputs.size()); std::vector<uint32_t> globalIndices; globalIndices.reserve(transaction.outputs.size()); if (!transactionDetails.inBlockchain || !core.get_tx_outputs_gindexs(hash, globalIndices)) { for (size_t i = 0; i < transaction.outputs.size(); ++i) { globalIndices.push_back(0); } } typedef boost::tuple<TransactionOutput, uint32_t> outputWithIndex; auto range = boost::combine(transaction.outputs, globalIndices); for (const outputWithIndex& txOutput : range) { TransactionOutputDetails txOutDetails; txOutDetails.amount = txOutput.get<0>().amount; txOutDetails.globalIndex = txOutput.get<1>(); if (txOutput.get<0>().target.type() == typeid(KeyOutput)) { TransactionOutputToKeyDetails txOutToKeyDetails; txOutToKeyDetails.txOutKey = boost::get<KeyOutput>(txOutput.get<0>().target).key; txOutDetails.output = txOutToKeyDetails; } else if (txOutput.get<0>().target.type() == typeid(MultisignatureOutput)) { TransactionOutputMultisignatureDetails txOutMultisigDetails; MultisignatureOutput txOutMultisig = boost::get<MultisignatureOutput>(txOutput.get<0>().target); txOutMultisigDetails.keys.reserve(txOutMultisig.keys.size()); for (const Crypto::PublicKey& key : txOutMultisig.keys) { txOutMultisigDetails.keys.push_back(std::move(key)); } txOutMultisigDetails.requiredSignatures = txOutMultisig.requiredSignatureCount; txOutDetails.output = txOutMultisigDetails; } else { return false; } transactionDetails.outputs.push_back(std::move(txOutDetails)); } return true; }
void serialize(ParentBlockSerializer& pbs, ISerializer& serializer) { serializer(pbs.m_parentBlock.majorVersion, "majorVersion"); serializer(pbs.m_parentBlock.minorVersion, "minorVersion"); serializer(pbs.m_timestamp, "timestamp"); serializer(pbs.m_parentBlock.previousBlockHash, "prevId"); serializer.binary(&pbs.m_nonce, sizeof(pbs.m_nonce), "nonce"); if (pbs.m_hashingSerialization) { Crypto::Hash minerTxHash; if (!getObjectHash(pbs.m_parentBlock.baseTransaction, minerTxHash)) { throw std::runtime_error("Get transaction hash error"); } Crypto::Hash merkleRoot; Crypto::tree_hash_from_branch(pbs.m_parentBlock.baseTransactionBranch.data(), pbs.m_parentBlock.baseTransactionBranch.size(), minerTxHash, 0, merkleRoot); serializer(merkleRoot, "merkleRoot"); } uint64_t txNum = static_cast<uint64_t>(pbs.m_parentBlock.transactionCount); serializer(txNum, "numberOfTransactions"); pbs.m_parentBlock.transactionCount = static_cast<uint16_t>(txNum); if (pbs.m_parentBlock.transactionCount < 1) { throw std::runtime_error("Wrong transactions number"); } if (pbs.m_headerOnly) { return; } size_t branchSize = Crypto::tree_depth(pbs.m_parentBlock.transactionCount); if (serializer.type() == ISerializer::OUTPUT) { if (pbs.m_parentBlock.baseTransactionBranch.size() != branchSize) { throw std::runtime_error("Wrong miner transaction branch size"); } } else { pbs.m_parentBlock.baseTransactionBranch.resize(branchSize); } // serializer(m_parentBlock.baseTransactionBranch, "baseTransactionBranch"); //TODO: Make arrays with computable size! This code won't work with json serialization! for (Crypto::Hash& hash: pbs.m_parentBlock.baseTransactionBranch) { serializer(hash, ""); } serializer(pbs.m_parentBlock.baseTransaction, "minerTx"); TransactionExtraMergeMiningTag mmTag; if (!getMergeMiningTagFromExtra(pbs.m_parentBlock.baseTransaction.extra, mmTag)) { throw std::runtime_error("Can't get extra merge mining tag"); } if (mmTag.depth > 8 * sizeof(Crypto::Hash)) { throw std::runtime_error("Wrong merge mining tag depth"); } if (serializer.type() == ISerializer::OUTPUT) { if (mmTag.depth != pbs.m_parentBlock.blockchainBranch.size()) { throw std::runtime_error("Blockchain branch size must be equal to merge mining tag depth"); } } else { pbs.m_parentBlock.blockchainBranch.resize(mmTag.depth); } // serializer(m_parentBlock.blockchainBranch, "blockchainBranch"); //TODO: Make arrays with computable size! This code won't work with json serialization! for (Crypto::Hash& hash: pbs.m_parentBlock.blockchainBranch) { serializer(hash, ""); } }