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();
}
예제 #2
0
void TransfersConsumer::processOutputs(const TransactionBlockInfo& blockInfo, TransfersSubscription& sub, const ITransactionReader& tx,
  const std::vector<TransactionOutputInformationIn>& transfers, const std::vector<uint32_t>& globalIdxs, bool& contains, bool& updated) {

  TransactionInformation subscribtionTxInfo;
  contains = sub.getContainer().getTransactionInformation(tx.getTransactionHash(), subscribtionTxInfo);
  updated = false;

  if (contains) {
    if (subscribtionTxInfo.blockHeight == WALLET_UNCONFIRMED_TRANSACTION_HEIGHT && blockInfo.height != WALLET_UNCONFIRMED_TRANSACTION_HEIGHT) {
      // pool->blockchain
      sub.markTransactionConfirmed(blockInfo, tx.getTransactionHash(), globalIdxs);
      updated = true;
    } else {
      assert(subscribtionTxInfo.blockHeight == blockInfo.height);
    }
  } else {
    auto messages = get_messages_from_extra(tx.getExtra(), tx.getTransactionPublicKey(), &sub.getKeys().spendSecretKey);
    updated = sub.addTransaction(blockInfo, tx, transfers, std::move(messages));
    contains = updated;
  }
}
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();
}