std::error_code createTransfers( const AccountKeys& account, const TransactionBlockInfo& blockInfo, const ITransactionReader& tx, const std::vector<uint32_t>& outputs, const std::vector<uint32_t>& globalIdxs, std::vector<TransactionOutputInformationIn>& transfers) { auto txPubKey = tx.getTransactionPublicKey(); for (auto idx : outputs) { if (idx >= tx.getOutputCount()) { return std::make_error_code(std::errc::argument_out_of_domain); } auto outType = tx.getOutputType(size_t(idx)); if ( outType != TransactionTypes::OutputType::Key) { continue; } TransactionOutputInformationIn info; info.type = outType; info.transactionPublicKey = txPubKey; info.outputInTransaction = idx; info.globalOutputIndex = (blockInfo.height == WALLET_UNCONFIRMED_TRANSACTION_HEIGHT) ? UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX : globalIdxs[idx]; if (outType == TransactionTypes::OutputType::Key) { uint64_t amount; KeyOutput out; tx.getOutput(idx, out, amount); CryptoNote::KeyPair in_ephemeral; CryptoNote::generate_key_image_helper( account, txPubKey, idx, in_ephemeral, info.keyImage); assert(out.key == reinterpret_cast<const PublicKey&>(in_ephemeral.publicKey)); info.amount = amount; info.outputKey = out.key; } transfers.push_back(info); } return std::error_code(); }
std::error_code TransfersConsumer::processOutputs(const BlockInfo& blockInfo, TransfersSubscription& sub, const ITransactionReader& tx, const std::vector<uint32_t>& outputs, const std::vector<uint64_t>& globalIdxs) { if (blockInfo.height != UNCONFIRMED_TRANSACTION_HEIGHT) { TransactionInformation subscribtionTxInfo; int64_t txBalance; if (sub.getContainer().getTransactionInformation(tx.getTransactionHash(), subscribtionTxInfo, txBalance)) { if (subscribtionTxInfo.blockHeight == UNCONFIRMED_TRANSACTION_HEIGHT) { // pool->blockchain sub.markTransactionConfirmed(blockInfo, tx.getTransactionHash(), globalIdxs); return std::error_code(); } else { // - Subscription already has this transaction as confirmed, so why are we here? // - Because, for instance, some another subscription doesn't have this transactions, so it is given to us again. return std::error_code(); } } } std::vector<TransactionOutputInformationIn> transfers; auto txPubKey = tx.getTransactionPublicKey(); for (auto idx : outputs) { if (idx >= tx.getOutputCount()) { return std::make_error_code(std::errc::argument_out_of_domain); } auto outType = tx.getOutputType(size_t(idx)); if ( outType != TransactionTypes::OutputType::Key && outType != TransactionTypes::OutputType::Multisignature) { continue; } TransactionOutputInformationIn info; info.type = outType; info.transactionPublicKey = txPubKey; info.outputInTransaction = idx; info.globalOutputIndex = (blockInfo.height == UNCONFIRMED_TRANSACTION_HEIGHT) ? UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX : globalIdxs[idx]; if (outType == TransactionTypes::OutputType::Key) { TransactionTypes::OutputKey out; tx.getOutput(idx, out); cryptonote::KeyPair in_ephemeral; cryptonote::generate_key_image_helper( reinterpret_cast<const cryptonote::account_keys&>(sub.getKeys()), reinterpret_cast<const crypto::public_key&>(txPubKey), idx, in_ephemeral, reinterpret_cast<crypto::key_image&>(info.keyImage)); assert(out.key == reinterpret_cast<const PublicKey&>(in_ephemeral.pub)); info.amount = out.amount; info.outputKey = out.key; } else if (outType == TransactionTypes::OutputType::Multisignature) { TransactionTypes::OutputMultisignature out; tx.getOutput(idx, out); info.amount = out.amount; info.requiredSignatures = out.requiredSignatures; } transfers.push_back(info); } sub.addTransaction(blockInfo, tx, transfers); return std::error_code(); }