// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "InProcessNode.h" #include #include #include #include "CryptoNoteConfig.h" #include "Common/StringTools.h" #include "CryptoNoteCore/CryptoNoteTools.h" #include "CryptoNoteCore/IBlock.h" #include "CryptoNoteCore/VerificationContext.h" #include "CryptoNoteProtocol/CryptoNoteProtocolHandlerCommon.h" #include "InProcessNodeErrors.h" #include "Common/StringTools.h" using namespace Crypto; using namespace Common; namespace CryptoNote { InProcessNode::InProcessNode(CryptoNote::ICore& core, CryptoNote::ICryptoNoteProtocolQuery& protocol) : state(NOT_INITIALIZED), core(core), protocol(protocol), blockchainExplorerDataBuilder(core, protocol) { } InProcessNode::~InProcessNode() { doShutdown(); } bool InProcessNode::addObserver(INodeObserver* observer) { if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return observerManager.add(observer); } bool InProcessNode::removeObserver(INodeObserver* observer) { if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return observerManager.remove(observer); } void InProcessNode::init(const Callback& callback) { std::unique_lock lock(mutex); std::error_code ec; if (state != NOT_INITIALIZED) { ec = make_error_code(CryptoNote::error::ALREADY_INITIALIZED); } else { protocol.addObserver(this); core.addObserver(this); work.reset(new boost::asio::io_service::work(ioService)); workerThread.reset(new std::thread(&InProcessNode::workerFunc, this)); state = INITIALIZED; } ioService.post(std::bind(callback, ec)); } bool InProcessNode::shutdown() { return doShutdown(); } bool InProcessNode::doShutdown() { std::unique_lock lock(mutex); if (state != INITIALIZED) { return false; } protocol.removeObserver(this); core.removeObserver(this); state = NOT_INITIALIZED; work.reset(); ioService.stop(); workerThread->join(); ioService.reset(); return true; } void InProcessNode::workerFunc() { ioService.run(); } void InProcessNode::getNewBlocks(std::vector&& knownBlockIds, std::vector& newBlocks, uint32_t& startHeight, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind(&InProcessNode::getNewBlocksAsync, this, std::move(knownBlockIds), std::ref(newBlocks), std::ref(startHeight), callback ) ); } void InProcessNode::getNewBlocksAsync(std::vector& knownBlockIds, std::vector& newBlocks, uint32_t& startHeight, const Callback& callback) { std::error_code ec = doGetNewBlocks(std::move(knownBlockIds), newBlocks, startHeight); callback(ec); } //it's always protected with mutex std::error_code InProcessNode::doGetNewBlocks(std::vector&& knownBlockIds, std::vector& newBlocks, uint32_t& startHeight) { { std::unique_lock lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { // TODO code duplication see RpcServer::on_get_blocks() if (knownBlockIds.empty()) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } if (knownBlockIds.back() != core.getBlockIdByHeight(0)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } uint32_t totalBlockCount; std::vector supplement = core.findBlockchainSupplement(knownBlockIds, CryptoNote::COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, totalBlockCount, startHeight); for (const auto& blockId : supplement) { assert(core.have_block(blockId)); auto completeBlock = core.getBlock(blockId); assert(completeBlock != nullptr); CryptoNote::block_complete_entry be; be.block = asString(toBinaryArray(completeBlock->getBlock())); be.txs.reserve(completeBlock->getTransactionCount()); for (size_t i = 0; i < completeBlock->getTransactionCount(); ++i) { be.txs.push_back(asString(toBinaryArray(completeBlock->getTransaction(i)))); } newBlocks.push_back(std::move(be)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector& outsGlobalIndices, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind(&InProcessNode::getTransactionOutsGlobalIndicesAsync, this, std::cref(transactionHash), std::ref(outsGlobalIndices), callback ) ); } void InProcessNode::getTransactionOutsGlobalIndicesAsync(const Crypto::Hash& transactionHash, std::vector& outsGlobalIndices, const Callback& callback) { std::error_code ec = doGetTransactionOutsGlobalIndices(transactionHash, outsGlobalIndices); callback(ec); } //it's always protected with mutex std::error_code InProcessNode::doGetTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector& outsGlobalIndices) { { std::unique_lock lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { bool r = core.get_tx_outputs_gindexs(transactionHash, outsGlobalIndices); if(!r) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getRandomOutsByAmounts(std::vector&& amounts, uint64_t outsCount, std::vector& result, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind(&InProcessNode::getRandomOutsByAmountsAsync, this, std::move(amounts), outsCount, std::ref(result), callback ) ); } void InProcessNode::getRandomOutsByAmountsAsync(std::vector& amounts, uint64_t outsCount, std::vector& result, const Callback& callback) { std::error_code ec = doGetRandomOutsByAmounts(std::move(amounts), outsCount, result); callback(ec); } //it's always protected with mutex std::error_code InProcessNode::doGetRandomOutsByAmounts(std::vector&& amounts, uint64_t outsCount, std::vector& result) { { std::unique_lock lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response res; CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req; req.amounts = amounts; req.outs_count = outsCount; if(!core.get_random_outs_for_amounts(req, res)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } result = std::move(res.outs); } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::relayTransaction(const CryptoNote::Transaction& transaction, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind(&InProcessNode::relayTransactionAsync, this, transaction, callback ) ); } void InProcessNode::relayTransactionAsync(const CryptoNote::Transaction& transaction, const Callback& callback) { std::error_code ec = doRelayTransaction(transaction); callback(ec); } //it's always protected with mutex std::error_code InProcessNode::doRelayTransaction(const CryptoNote::Transaction& transaction) { { std::unique_lock lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { CryptoNote::BinaryArray transactionBinaryArray = toBinaryArray(transaction); CryptoNote::tx_verification_context tvc = boost::value_initialized(); if (!core.handle_incoming_tx(transactionBinaryArray, tvc, false)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } if(tvc.m_verifivation_failed) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } if(!tvc.m_should_be_relayed) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } CryptoNote::NOTIFY_NEW_TRANSACTIONS::request r; r.txs.push_back(asString(transactionBinaryArray)); core.get_protocol()->relay_transactions(r); } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } size_t InProcessNode::getPeerCount() const { { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } return protocol.getPeerCount(); } uint32_t InProcessNode::getLocalBlockCount() const { { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } uint32_t lastIndex; Crypto::Hash ignore; core.get_blockchain_top(lastIndex, ignore); return lastIndex + 1; } uint32_t InProcessNode::getKnownBlockCount() const { { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } return protocol.getObservedHeight(); } uint32_t InProcessNode::getLastLocalBlockHeight() const { { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } uint32_t height; Crypto::Hash ignore; core.get_blockchain_top(height, ignore); return height; } uint32_t InProcessNode::getLastKnownBlockHeight() const { { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } return protocol.getObservedHeight() - 1; } uint64_t InProcessNode::getLastLocalBlockTimestamp() const { std::unique_lock lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } lock.unlock(); uint32_t ignore; Crypto::Hash hash; core.get_blockchain_top(ignore, hash); CryptoNote::Block block; if (!core.getBlockByHash(hash, block)) { throw std::system_error(make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR)); } return block.timestamp; } void InProcessNode::peerCountUpdated(size_t count) { observerManager.notify(&INodeObserver::peerCountUpdated, count); } void InProcessNode::lastKnownBlockHeightUpdated(uint32_t height) { observerManager.notify(&INodeObserver::lastKnownBlockHeightUpdated, height); } void InProcessNode::blockchainUpdated() { uint32_t height; Crypto::Hash ignore; core.get_blockchain_top(height, ignore); observerManager.notify(&INodeObserver::localBlockchainUpdated, height); } void InProcessNode::poolUpdated() { observerManager.notify(&INodeObserver::poolChanged); } void InProcessNode::blockchainSynchronized(uint32_t topHeight) { observerManager.notify(&INodeObserver::blockchainSynchronized, topHeight); } void InProcessNode::queryBlocks(std::vector&& knownBlockIds, uint64_t timestamp, std::vector& newBlocks, uint32_t& startHeight, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind(&InProcessNode::queryBlocksLiteAsync, this, std::move(knownBlockIds), timestamp, std::ref(newBlocks), std::ref(startHeight), callback ) ); } void InProcessNode::queryBlocksLiteAsync(std::vector& knownBlockIds, uint64_t timestamp, std::vector& newBlocks, uint32_t& startHeight, const Callback& callback) { std::error_code ec = doQueryBlocksLite(std::move(knownBlockIds), timestamp, newBlocks, startHeight); callback(ec); } std::error_code InProcessNode::doQueryBlocksLite(std::vector&& knownBlockIds, uint64_t timestamp, std::vector& newBlocks, uint32_t& startHeight) { uint32_t currentHeight, fullOffset; std::vector entries; if (!core.queryBlocksLite(knownBlockIds, timestamp, startHeight, currentHeight, fullOffset, entries)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } for (const auto& entry: entries) { BlockShortEntry bse; bse.blockHash = entry.blockId; bse.hasBlock = false; if (!entry.block.empty()) { bse.hasBlock = true; if (!fromBinaryArray(bse.block, asBinaryArray(entry.block))) { return std::make_error_code(std::errc::invalid_argument); } } for (const auto& tsi: entry.txPrefixes) { TransactionShortInfo tpi; tpi.txId = tsi.txHash; tpi.txPrefix = tsi.txPrefix; bse.txsShortInfo.push_back(std::move(tpi)); } newBlocks.push_back(std::move(bse)); } return std::error_code(); } void InProcessNode::getPoolSymmetricDifference(std::vector&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual, std::vector>& newTxs, std::vector& deletedTxIds, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post([this, knownPoolTxIds, knownBlockId, &isBcActual, &newTxs, &deletedTxIds, callback] () mutable { this->getPoolSymmetricDifferenceAsync(std::move(knownPoolTxIds), knownBlockId, isBcActual, newTxs, deletedTxIds, callback); }); } void InProcessNode::getPoolSymmetricDifferenceAsync(std::vector&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual, std::vector>& newTxs, std::vector& deletedTxIds, const Callback& callback) { std::error_code ec = std::error_code(); std::vector added; isBcActual = core.getPoolChangesLite(knownBlockId, knownPoolTxIds, added, deletedTxIds); try { for (const auto& tx: added) { newTxs.push_back(createTransactionPrefix(tx.txPrefix, tx.txHash)); } } catch (std::system_error& ex) { ec = ex.code(); } catch (std::exception&) { ec = make_error_code(std::errc::invalid_argument); } callback(ec); } void InProcessNode::getMultisignatureOutputByGlobalIndex(uint64_t amount, uint32_t gindex, MultisignatureOutput& out, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post([this, amount, gindex, &out, callback]() mutable { this->getOutByMSigGIndexAsync(amount, gindex, out, callback); }); } void InProcessNode::getOutByMSigGIndexAsync(uint64_t amount, uint32_t gindex, MultisignatureOutput& out, const Callback& callback) { std::error_code ec = std::error_code(); bool result = core.getOutByMSigGIndex(amount, gindex, out); if (!result) { ec = make_error_code(std::errc::invalid_argument); callback(ec); return; } callback(ec); } void InProcessNode::getBlocks(const std::vector& blockHeights, std::vector>& blocks, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( static_cast< void(InProcessNode::*)( const std::vector&, std::vector>&, const Callback& ) >(&InProcessNode::getBlocksAsync), this, std::cref(blockHeights), std::ref(blocks), callback ) ); } void InProcessNode::getBlocksAsync(const std::vector& blockHeights, std::vector>& blocks, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( static_cast< std::error_code(InProcessNode::*)( const std::vector&, std::vector>& ) >(&InProcessNode::doGetBlocks), this, std::cref(blockHeights), std::ref(blocks) ) ); callback(ec); } std::error_code InProcessNode::doGetBlocks(const std::vector& blockHeights, std::vector>& blocks) { try { uint32_t topHeight = 0; Crypto::Hash topHash = boost::value_initialized(); core.get_blockchain_top(topHeight, topHash); for (const uint32_t& height : blockHeights) { if (height > topHeight) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } Crypto::Hash hash = core.getBlockIdByHeight(height); Block block; if (!core.getBlockByHash(hash, block)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } BlockDetails blockDetails; if (!blockchainExplorerDataBuilder.fillBlockDetails(block, blockDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } std::vector blocksOnSameHeight; blocksOnSameHeight.push_back(std::move(blockDetails)); //Getting orphans std::vector orphanBlocks; core.getOrphanBlocksByHeight(height, orphanBlocks); for (const Block& orphanBlock : orphanBlocks) { BlockDetails orphanBlockDetails; if (!blockchainExplorerDataBuilder.fillBlockDetails(orphanBlock, orphanBlockDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } blocksOnSameHeight.push_back(std::move(orphanBlockDetails)); } blocks.push_back(std::move(blocksOnSameHeight)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getBlocks(const std::vector& blockHashes, std::vector& blocks, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( static_cast< void(InProcessNode::*)( const std::vector&, std::vector&, const Callback& ) >(&InProcessNode::getBlocksAsync), this, std::cref(blockHashes), std::ref(blocks), callback ) ); } void InProcessNode::getBlocksAsync(const std::vector& blockHashes, std::vector& blocks, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( static_cast< std::error_code(InProcessNode::*)( const std::vector&, std::vector& ) >(&InProcessNode::doGetBlocks), this, std::cref(blockHashes), std::ref(blocks) ) ); callback(ec); } std::error_code InProcessNode::doGetBlocks(const std::vector& blockHashes, std::vector& blocks) { try { for (const Crypto::Hash& hash : blockHashes) { Block block; if (!core.getBlockByHash(hash, block)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } BlockDetails blockDetails; if (!blockchainExplorerDataBuilder.fillBlockDetails(block, blockDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } blocks.push_back(std::move(blockDetails)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getBlocks(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector& blocks, uint32_t& blocksNumberWithinTimestamps, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( static_cast< void(InProcessNode::*)( uint64_t, uint64_t, uint32_t, std::vector&, uint32_t&, const Callback& ) >(&InProcessNode::getBlocksAsync), this, timestampBegin, timestampEnd, blocksNumberLimit, std::ref(blocks), std::ref(blocksNumberWithinTimestamps), callback ) ); } void InProcessNode::getBlocksAsync(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector& blocks, uint32_t& blocksNumberWithinTimestamps, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( static_cast< std::error_code(InProcessNode::*)( uint64_t, uint64_t, uint32_t, std::vector&, uint32_t& ) >(&InProcessNode::doGetBlocks), this, timestampBegin, timestampEnd, blocksNumberLimit, std::ref(blocks), std::ref(blocksNumberWithinTimestamps) ) ); callback(ec); } std::error_code InProcessNode::doGetBlocks(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t blocksNumberLimit, std::vector& blocks, uint32_t& blocksNumberWithinTimestamps) { try { std::vector rawBlocks; if (!core.getBlocksByTimestamp(timestampBegin, timestampEnd, blocksNumberLimit, rawBlocks, blocksNumberWithinTimestamps)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } for (const Block& rawBlock : rawBlocks) { BlockDetails block; if (!blockchainExplorerDataBuilder.fillBlockDetails(rawBlock, block)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } blocks.push_back(std::move(block)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getTransactions(const std::vector& transactionHashes, std::vector& transactions, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( static_cast< void(InProcessNode::*)( const std::vector&, std::vector&, const Callback& ) >(&InProcessNode::getTransactionsAsync), this, std::cref(transactionHashes), std::ref(transactions), callback ) ); } void InProcessNode::getTransactionsAsync(const std::vector& transactionHashes, std::vector& transactions, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( static_cast< std::error_code(InProcessNode::*)( const std::vector&, std::vector& ) >(&InProcessNode::doGetTransactions), this, std::cref(transactionHashes), std::ref(transactions) ) ); callback(ec); } std::error_code InProcessNode::doGetTransactions(const std::vector& transactionHashes, std::vector& transactions) { try { std::list txs; std::list missed_txs; core.getTransactions(transactionHashes, txs, missed_txs, true); if (missed_txs.size() > 0) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } for (const Transaction& tx : txs) { TransactionDetails transactionDetails; if (!blockchainExplorerDataBuilder.fillTransactionDetails(tx, transactionDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } transactions.push_back(std::move(transactionDetails)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getPoolTransactions(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector& transactions, uint64_t& transactionsNumberWithinTimestamps, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( &InProcessNode::getPoolTransactionsAsync, this, timestampBegin, timestampEnd, transactionsNumberLimit, std::ref(transactions), std::ref(transactionsNumberWithinTimestamps), callback ) ); } void InProcessNode::getPoolTransactionsAsync(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector& transactions, uint64_t& transactionsNumberWithinTimestamps, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( &InProcessNode::doGetPoolTransactions, this, timestampBegin, timestampEnd, transactionsNumberLimit, std::ref(transactions), std::ref(transactionsNumberWithinTimestamps) ) ); callback(ec); } std::error_code InProcessNode::doGetPoolTransactions(uint64_t timestampBegin, uint64_t timestampEnd, uint32_t transactionsNumberLimit, std::vector& transactions, uint64_t& transactionsNumberWithinTimestamps) { try { std::vector rawTransactions; if (!core.getPoolTransactionsByTimestamp(timestampBegin, timestampEnd, transactionsNumberLimit, rawTransactions, transactionsNumberWithinTimestamps)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } for (const Transaction& rawTransaction : rawTransactions) { TransactionDetails transactionDetails; if (!blockchainExplorerDataBuilder.fillTransactionDetails(rawTransaction, transactionDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } transactions.push_back(std::move(transactionDetails)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::getTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector& transactions, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( &InProcessNode::getTransactionsByPaymentIdAsync, this, std::cref(paymentId), std::ref(transactions), callback ) ); } void InProcessNode::getTransactionsByPaymentIdAsync(const Crypto::Hash& paymentId, std::vector& transactions, const Callback& callback) { std::error_code ec = core.executeLocked( std::bind( &InProcessNode::doGetTransactionsByPaymentId, this, paymentId, std::ref(transactions) ) ); callback(ec); } std::error_code InProcessNode::doGetTransactionsByPaymentId(const Crypto::Hash& paymentId, std::vector& transactions) { try { std::vector rawTransactions; if (!core.getTransactionsByPaymentId(paymentId, rawTransactions)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } for (const Transaction& rawTransaction : rawTransactions) { TransactionDetails transactionDetails; if (!blockchainExplorerDataBuilder.fillTransactionDetails(rawTransaction, transactionDetails)) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } transactions.push_back(std::move(transactionDetails)); } } catch (std::system_error& e) { return e.code(); } catch (std::exception&) { return make_error_code(CryptoNote::error::INTERNAL_NODE_ERROR); } return std::error_code(); } void InProcessNode::isSynchronized(bool& syncStatus, const Callback& callback) { std::unique_lock lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } ioService.post( std::bind( &InProcessNode::isSynchronizedAsync, this, std::ref(syncStatus), callback ) ); } void InProcessNode::isSynchronizedAsync(bool& syncStatus, const Callback& callback) { syncStatus = protocol.isSynchronized(); callback(std::error_code()); } } //namespace CryptoNote