private std::error_code preprocessOutputs(TransactionBlockInfo blockInfo, ITransactionReader tx, PreprocessInfo info) { Dictionary <PublicKey, List <uint> > outputs = new Dictionary <PublicKey, List <uint> >(); try { GlobalMembers.findMyOutputs(tx, m_viewSecret, m_spendKeys, outputs); } catch (System.Exception e) { m_logger.functorMethod(WARNING, BRIGHT_RED) << "Failed to process transaction: " << e.Message << ", transaction hash " << Common.GlobalMembers.podToHex(tx.GetTransactionHash()); return(std::error_code()); } if (outputs.Count == 0) { return(std::error_code()); } std::error_code errorCode = new std::error_code(); var txHash = tx.GetTransactionHash(); if (blockInfo.height != GlobalMembers.WALLET_UNCONFIRMED_TRANSACTION_HEIGHT) { //C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#: //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: errorCode = getGlobalIndices(reinterpret_cast<const Hash&>(txHash), info.globalIdxs); errorCode.CopyFrom(getGlobalIndices(reinterpret_cast <const Hash&>(txHash), info.globalIdxs)); if (errorCode != null) { return(errorCode); } } foreach (var kv in outputs) { var it = m_subscriptions.find(kv.first); //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops: if (it != m_subscriptions.end()) { auto transfers = info.outputs[kv.first]; //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: errorCode = createTransfers(it->second->getKeys(), blockInfo, tx, kv.second, info.globalIdxs, transfers, m_logger); //C++ TO C# CONVERTER TODO TASK: Iterators are only converted within the context of 'while' and 'for' loops: errorCode.CopyFrom(CryptoNote.GlobalMembers.createTransfers(it.second.getKeys(), blockInfo, tx, kv.second, info.globalIdxs, transfers, m_logger.functorMethod)); if (errorCode != null) { return(errorCode); } } } return(std::error_code()); }
public override std::error_code onPoolUpdated(List <std::unique_ptr <ITransactionReader> > addedTransactions, List <Hash> deletedTransactions) { TransactionBlockInfo unconfirmedBlockInfo = new TransactionBlockInfo(); unconfirmedBlockInfo.timestamp = 0; unconfirmedBlockInfo.height = GlobalMembers.WALLET_UNCONFIRMED_TRANSACTION_HEIGHT; std::error_code processingError = new std::error_code(); foreach (var cryptonoteTransaction in addedTransactions) { m_poolTxs.emplace(cryptonoteTransaction.getTransactionHash()); //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: processingError = processTransaction(unconfirmedBlockInfo, *cryptonoteTransaction.get()); processingError.CopyFrom(processTransaction(unconfirmedBlockInfo, *cryptonoteTransaction.get())); if (processingError != null) { foreach (var sub in m_subscriptions) { sub.second.onError(processingError, GlobalMembers.WALLET_UNCONFIRMED_TRANSACTION_HEIGHT); } return(processingError); } } foreach (var deletedTxHash in deletedTransactions) { m_poolTxs.erase(deletedTxHash); m_observerManager.notify(IBlockchainConsumerObserver.onTransactionDeleteBegin, this, deletedTxHash); foreach (var sub in m_subscriptions) { //C++ TO C# CONVERTER TODO TASK: There is no equivalent to 'reinterpret_cast' in C#: sub.second.deleteUnconfirmedTransaction(*reinterpret_cast <const Hash>(deletedTxHash)); } m_observerManager.notify(IBlockchainConsumerObserver.onTransactionDeleteEnd, this, deletedTxHash); } return(std::error_code()); }
public override uint onNewBlocks(CompleteBlock[] blocks, uint startHeight, uint count) { Debug.Assert(blocks); Debug.Assert(count > 0); //C++ TO C# CONVERTER TODO TASK: C# does not allow declaring types within methods: // struct Tx // { // TransactionBlockInfo blockInfo; // const ITransactionReader* tx; // bool isLastTransactionInBlock; // }; //C++ TO C# CONVERTER TODO TASK: C# does not allow declaring types within methods: // struct PreprocessedTx : Tx, PreprocessInfo // { // }; List <PreprocessedTx> preprocessedTransactions = new List <PreprocessedTx>(); object preprocessedTransactionsMutex = new object(); uint workers = std::thread.hardware_concurrency(); if (workers == 0) { workers = 2; } BlockingQueue <Tx> inputQueue = new BlockingQueue <Tx>(workers * 2); std::atomic <bool> stopProcessing = new std::atomic <bool>(false); std::atomic <uint> emptyBlockCount = new std::atomic <uint>(0); //C++ TO C# CONVERTER TODO TASK: Lambda expressions cannot be assigned to 'var': var pushingThread = std::async(std::launch.async, () => { for (uint i = 0; i < count && stopProcessing == null; ++i) { auto block = blocks[i].block; if (!block.is_initialized()) { ++emptyBlockCount; continue; } // filter by syncStartTimestamp if (m_syncStart.timestamp != 0 && block.timestamp < m_syncStart.timestamp) { ++emptyBlockCount; continue; } TransactionBlockInfo blockInfo = new TransactionBlockInfo(); blockInfo.height = startHeight + i; blockInfo.timestamp = block.timestamp; blockInfo.transactionIndex = 0; // position in block foreach (var tx in blocks[i].transactions) { var pubKey = tx.GetTransactionPublicKey(); if (pubKey == NULL_PUBLIC_KEY) { ++blockInfo.transactionIndex; continue; } bool isLastTransactionInBlock = blockInfo.transactionIndex + 1 == blocks[i].transactions.size(); Tx item = new Tx(blockInfo, tx.get(), isLastTransactionInBlock); inputQueue.push(new Tx(item)); ++blockInfo.transactionIndex; } } inputQueue.close(); }); //C++ TO C# CONVERTER TODO TASK: Lambda expressions cannot be assigned to 'var': var processingFunction = () => { Tx item = new Tx(); std::error_code ec = new std::error_code(); while (stopProcessing == null && inputQueue.pop(ref item)) { PreprocessedTx output = new PreprocessedTx(); (Tx)output = item; ec.CopyFrom(preprocessOutputs(item.blockInfo, *item.tx, output)); if (ec != null) { stopProcessing = true; break; } lock (preprocessedTransactionsMutex) { preprocessedTransactions.Add(std::move(output)); } } return(ec); }; List <std::future <std::error_code> > processingThreads = new List <std::future <std::error_code> >(); for (uint i = 0; i < workers; ++i) { processingThreads.Add(std::async(std::launch.async, processingFunction)); } std::error_code processingError = new std::error_code(); foreach (var f in processingThreads) { try { std::error_code ec = f.get(); if (processingError == null && ec != null) { //C++ TO C# CONVERTER TODO TASK: The following line was determined to be a copy assignment (rather than a reference assignment) - this should be verified and a 'CopyFrom' method should be created: //ORIGINAL LINE: processingError = ec; processingError.CopyFrom(ec); } } catch (std::system_error e) { processingError = e.code(); } catch (System.Exception) { processingError = std::make_error_code(std::errc.operation_canceled); } } if (processingError != null) { forEachSubscription((TransfersSubscription sub) => { sub.onError(processingError, startHeight); }); return(0); } //C++ TO C# CONVERTER TODO TASK: The following line was determined to contain a copy constructor call - this should be verified and a copy constructor should be created: //ORIGINAL LINE: ClassicVector<Crypto::Hash> blockHashes = getBlockHashes(blocks, count); List <Crypto.Hash> blockHashes = GlobalMembers.getBlockHashes(new CryptoNote.CompleteBlock(blocks), count); m_observerManager.notify(IBlockchainConsumerObserver.onBlocksAdded, this, blockHashes); // sort by block height and transaction index in block //C++ TO C# CONVERTER TODO TASK: The 'Compare' parameter of std::sort produces a boolean value, while the .NET Comparison parameter produces a tri-state result: //ORIGINAL LINE: std::sort(preprocessedTransactions.begin(), preprocessedTransactions.end(), [](const PreprocessedTx& a, const PreprocessedTx& b) preprocessedTransactions.Sort((PreprocessedTx a, PreprocessedTx b) => { return(std::tie(a.blockInfo.height, a.blockInfo.transactionIndex) < std::tie(b.blockInfo.height, b.blockInfo.transactionIndex)); }); uint processedBlockCount = (uint)emptyBlockCount; try { foreach (var tx in preprocessedTransactions) { processTransaction(tx.blockInfo, *tx.tx, tx); if (tx.isLastTransactionInBlock) { ++processedBlockCount; m_logger.functorMethod(TRACE) << "Processed block " << (int)processedBlockCount << " of " << (int)count << ", last processed block index " << tx.blockInfo.height << ", hash " << blocks[processedBlockCount - 1].blockHash; var newHeight = startHeight + processedBlockCount - 1; //C++ TO C# CONVERTER TODO TASK: Only lambda expressions having all locals passed by reference can be converted to C#: //ORIGINAL LINE: forEachSubscription([newHeight](TransfersSubscription& sub) forEachSubscription((TransfersSubscription sub) => { sub.advanceHeight(newHeight); }); } } } catch (MarkTransactionConfirmedException e) { m_logger.functorMethod(ERROR, BRIGHT_RED) << "Failed to process block transactions: failed to confirm transaction " << e.getTxHash() << ", remove this transaction from all containers and transaction pool"; forEachSubscription((TransfersSubscription sub) => { sub.deleteUnconfirmedTransaction(e.getTxHash()); }); m_poolTxs.erase(e.getTxHash()); } catch (System.Exception e) { m_logger.functorMethod(ERROR, BRIGHT_RED) << "Failed to process block transactions, exception: " << e.Message; } catch { m_logger.functorMethod(ERROR, BRIGHT_RED) << "Failed to process block transactions, unknown exception"; } if (processedBlockCount < count) { uint detachIndex = startHeight + processedBlockCount; m_logger.functorMethod(ERROR, BRIGHT_RED) << "Not all block transactions are processed, fully processed block count: " << (int)processedBlockCount << " of " << (int)count << ", last processed block hash " << (processedBlockCount > 0 ? blocks[processedBlockCount - 1].blockHash : GlobalMembers.NULL_HASH) << ", detach block index " << (int)detachIndex << " to remove partially processed block"; //C++ TO C# CONVERTER TODO TASK: Only lambda expressions having all locals passed by reference can be converted to C#: //ORIGINAL LINE: forEachSubscription([detachIndex](TransfersSubscription& sub) forEachSubscription((TransfersSubscription sub) => { sub.onBlockchainDetach(detachIndex); }); } return(processedBlockCount); }