See More

// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers // // This file is part of Bytecoin. // // Bytecoin is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Bytecoin is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Bytecoin. If not, see . #include "InProcessNode.h" #include #include #include #include #include #include "CryptoNoteConfig.h" #include "Common/StringTools.h" #include "Common/ScopeExit.h" #include "CryptoNoteCore/CryptoNoteTools.h" #include "CryptoNoteCore/VerificationContext.h" #include "CryptoNoteProtocol/CryptoNoteProtocolHandlerCommon.h" #include "InProcessNodeErrors.h" #include "Common/StringTools.h" using namespace Crypto; using namespace Common; namespace CryptoNote { namespace { //executes function in dispatcher's context from any thread //add specialisation when needed template class RemotelySpawnedSyncContext { public: RemotelySpawnedSyncContext(System::Dispatcher& dispatcher, std::atomic& counter, System::Event& counterEvent, std::function&& function) : called(false) { future = promise.get_future(); counter++; dispatcher.remoteSpawn([this, function, &counter, &counterEvent] () { Tools::ScopeExit guard([&counter, &counterEvent] () { counter--; counterEvent.set(); }); try { promise.set_value(function()); } catch (std::exception&) { promise.set_exception(std::current_exception()); } }); } ~RemotelySpawnedSyncContext() { try { if (!called) { future.get(); } } catch (std::exception&){ } } ReturnType get() { called = true; return future.get(); } RemotelySpawnedSyncContext(const RemotelySpawnedSyncContext&) = delete; RemotelySpawnedSyncContext& operator=(const RemotelySpawnedSyncContext&) = delete; RemotelySpawnedSyncContext(RemotelySpawnedSyncContext&&) = delete; RemotelySpawnedSyncContext& operator=(RemotelySpawnedSyncContext&&) = delete; private: std::promise promise; std::future future; std::atomic called; }; class RemoteContextCounterWrapper { public: RemoteContextCounterWrapper(System::Dispatcher& dispatcher_, std::function&& function_, std::atomic& contextCounter_, System::Event& contextCounterEvent_): dispatcher(dispatcher_), function(std::move(function_)), contextCounter(contextCounter_), contextCounterEvent(contextCounterEvent_) { } void operator()() { contextCounter++; Tools::ScopeExit guard([this] () { contextCounter--; contextCounterEvent.set(); }); System::RemoteContext remoteContext(dispatcher, [this] { function(); }); remoteContext.get(); } private: System::Dispatcher& dispatcher; std::function function; std::atomic& contextCounter; System::Event& contextCounterEvent; }; void remoteSpawn(System::Dispatcher& dispatcher, std::function&& func, std::atomic& contextCounter, System::Event& contextCounterEvent) { contextCounter++; dispatcher.remoteSpawn([func, &contextCounter, &contextCounterEvent] () { Tools::ScopeExit guard([&contextCounter, &contextCounterEvent] () { contextCounter--; contextCounterEvent.set(); }); func(); }); } uint64_t getBlockReward(const BlockTemplate& block) { uint64_t reward = 0; for (const TransactionOutput& out : block.baseTransaction.outputs) { reward += out.amount; } return reward; } } InProcessNode::InProcessNode(CryptoNote::ICore& core, CryptoNote::ICryptoNoteProtocolHandler& protocol, System::Dispatcher& disp) : state(NOT_INITIALIZED), contextGroup(dispatcher), contextCounter(0), contextCounterEvent(disp), core(core), protocol(protocol), messageQueue(dispatcher), dispatcher(disp) { resetLastLocalBlockHeaderInfo(); } 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<:mutex> lock(mutex); std::error_code ec; if (state != NOT_INITIALIZED) { ec = make_error_code(CryptoNote::error::ALREADY_INITIALIZED); executeInRemoteThread([callback, ec] { callback(ec); }); return; } protocol.addObserver(this); core.addMessageQueue(messageQueue); contextCounter++; contextGroup.spawn([this] { using namespace Messages; Tools::ScopeExit guard([this] () { contextCounter--; contextCounterEvent.set(); }); try { while (true) { messageQueue.front().match( [this](const NewBlock& msg) { auto topBlockIndex = this->core.getTopBlockIndex(); executeInRemoteThread([this, topBlockIndex] () { blockchainUpdated(topBlockIndex); }); }, [this](const NewAlternativeBlock& msg) { auto topBlockIndex = this->core.getTopBlockIndex(); executeInRemoteThread([this, topBlockIndex] () { blockchainUpdated(topBlockIndex); }); }, [this](const ChainSwitch& msg) { auto topBlockIndex = this->core.getTopBlockIndex(); executeInRemoteThread([this, msg, topBlockIndex] () { chainSwitched(topBlockIndex, msg.commonRootIndex, msg.blocksFromCommonRoot); blockchainUpdated(topBlockIndex); }); }, [this](const AddTransaction& msg) { executeInRemoteThread([this] () { poolUpdated(); }); }, [this](const DeleteTransaction& msg) { executeInRemoteThread([this] () { poolUpdated(); }); } ); messageQueue.pop(); } } catch (System::InterruptedException&) { } }); updateLastLocalBlockHeaderInfo(); state = INITIALIZED; executeInRemoteThread([callback, ec] { callback(ec); }); } bool InProcessNode::shutdown() { return doShutdown(); } bool InProcessNode::doShutdown() { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { return false; } protocol.removeObserver(this); core.removeMessageQueue(messageQueue); // TODO: add RAII guard resetLastLocalBlockHeaderInfo(); state = NOT_INITIALIZED; messageQueue.stop(); lock.unlock(); while(contextCounter > 0) { contextCounterEvent.wait(); contextCounterEvent.clear(); } return true; } //must be called from dispatcher's thread void InProcessNode::executeInRemoteThread(std::function&& func) { System::RemoteContext remoteContext(dispatcher, std::move(func)); remoteContext.get(); } //may be called from any thread void InProcessNode::executeInDispatcherThread(std::function&& func) { remoteSpawn(dispatcher, std::move(func), contextCounter, contextCounterEvent); } void InProcessNode::getNewBlocks(std::vector<:hash>&& knownBlockIds, std::vector<:rawblock>& newBlocks, uint32_t& startIndex, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([&newBlocks, &startIndex, callback, knownBlockIds, this] () mutable { auto ec = doGetNewBlocks(std::move(knownBlockIds), newBlocks, startIndex); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetNewBlocks(const std::vector<:hash>& knownBlockIds, std::vector<:rawblock>& newBlocks, uint32_t& startHeight) { { std::unique_lock<:mutex> 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); } auto blockTemplate = core.getBlockByIndex(0); if (knownBlockIds.back() != CryptoNote::CachedBlock(blockTemplate).getBlockHash()) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } uint32_t totalBlockCount; auto supplement = core.findBlockchainSupplement(knownBlockIds, CryptoNote::COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, totalBlockCount, startHeight); for (const auto& blockId : supplement) { assert(core.hasBlock(blockId)); auto completeBlock = core.getBlockByHash(blockId); RawBlock be; be.block = toBinaryArray(completeBlock); be.transactions.reserve(completeBlock.transactionHashes.size()); std::vector binaryTransactions; std::vector<:hash> missed; core.getTransactions(completeBlock.transactionHashes, binaryTransactions, missed); std::move(std::begin(binaryTransactions), std::end(binaryTransactions), std::back_inserter(be.transactions)); 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<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &outsGlobalIndices] () { auto ec = doGetTransactionOutsGlobalIndices(transactionHash, outsGlobalIndices); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetTransactionOutsGlobalIndices(const Crypto::Hash& transactionHash, std::vector& outsGlobalIndices) { { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { bool r = core.getTransactionGlobalIndexes(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, uint16_t outsCount, std::vector<:command_rpc_get_random_outputs_for_amounts::outs_for_amount>& result, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &result] () mutable { auto ec = doGetRandomOutsByAmounts(std::move(amounts), outsCount, result); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetRandomOutsByAmounts( std::vector&& amounts, uint16_t outsCount, std::vector<:command_rpc_get_random_outputs_for_amounts::outs_for_amount>& result) { { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response res; std::vector indices; std::vector<:publickey> keys; std::vector<:command_rpc_get_random_outputs_for_amounts::outs_for_amount> tmpResult; for (auto amount : amounts) { indices.clear(); keys.clear(); if (!core.getRandomOutputs(amount, outsCount, indices, keys)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } assert(indices.size() == keys.size()); CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outsForAmount; outsForAmount.amount = amount; for (size_t i = 0; i < indices.size(); ++i) { outsForAmount.outs.push_back( {indices[i], keys[i]} ); } tmpResult.push_back(std::move(outsForAmount)); } result = std::move(tmpResult); } 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<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=] () { auto ec = doRelayTransaction(transaction); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doRelayTransaction(const CryptoNote::Transaction& transaction) { { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { return make_error_code(CryptoNote::error::NOT_INITIALIZED); } } try { if (!core.addTransactionToPool(toBinaryArray(transaction))) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } protocol.relayTransactions({toBinaryArray(transaction)}); } 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<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } RemotelySpawnedSyncContext context(dispatcher, contextCounter, contextCounterEvent, [this] () { return protocol.getPeerCount(); }); return context.get(); } uint32_t InProcessNode::getLocalBlockCount() const { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return lastLocalBlockHeaderInfo.index + 1; } uint32_t InProcessNode::getKnownBlockCount() const { { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } RemotelySpawnedSyncContext context(dispatcher, contextCounter, contextCounterEvent, [this] { return protocol.getObservedHeight(); }); return context.get(); } uint32_t InProcessNode::getLastLocalBlockHeight() const { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return lastLocalBlockHeaderInfo.index; } uint32_t InProcessNode::getLastKnownBlockHeight() const { { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } } RemotelySpawnedSyncContext context(dispatcher, contextCounter, contextCounterEvent, [this] { return protocol.getObservedHeight() - 1; }); return context.get(); } uint64_t InProcessNode::getLastLocalBlockTimestamp() const { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return lastLocalBlockHeaderInfo.timestamp; } BlockHeaderInfo InProcessNode::getLastLocalBlockHeaderInfo() const { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } return lastLocalBlockHeaderInfo; } void InProcessNode::getBlockHashesByTimestamps(uint64_t timestampBegin, size_t secondsCount, std::vector<:hash>& blockHashes, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } lock.unlock(); executeInDispatcherThread([this, timestampBegin, secondsCount, &blockHashes, callback] () mutable { std::error_code ec; try { blockHashes = core.getBlockHashesByTimestamps(timestampBegin, secondsCount); } catch (std::system_error& e) { ec = e.code(); } catch (std::exception&) { ec = make_error_code(error::INTERNAL_NODE_ERROR); } executeInRemoteThread([callback, ec] () { callback(ec); }); }); } void InProcessNode::getTransactionHashesByPaymentId(const Crypto::Hash& paymentId, std::vector<:hash>& transactionHashes, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { throw std::system_error(make_error_code(CryptoNote::error::NOT_INITIALIZED)); } lock.unlock(); executeInDispatcherThread([this, &paymentId, &transactionHashes, callback] () mutable { std::error_code ec; try { transactionHashes = core.getTransactionHashesByPaymentId(paymentId); } catch (std::system_error& e) { ec = e.code(); } catch (std::exception&) { ec = make_error_code(error::INTERNAL_NODE_ERROR); } executeInRemoteThread([callback, ec] () { callback(ec); }); }); } void InProcessNode::peerCountUpdated(size_t count) { observerManager.notify(&INodeObserver::peerCountUpdated, count); } void InProcessNode::lastKnownBlockHeightUpdated(uint32_t height) { observerManager.notify(&INodeObserver::lastKnownBlockHeightUpdated, height - 1); } void InProcessNode::blockchainUpdated(uint32_t topBlockIndex) { std::unique_lock<:mutex> lock(mutex); updateLastLocalBlockHeaderInfo(); lock.unlock(); observerManager.notify(&INodeObserver::localBlockchainUpdated, topBlockIndex /*core.getTopBlockIndex()*/); } void InProcessNode::chainSwitched(uint32_t topBlockIndex, uint32_t commonRoot, const std::vector<:hash>& hashes) { observerManager.notify(&INodeObserver::chainSwitched, topBlockIndex, commonRoot, hashes); } void InProcessNode::poolUpdated() { observerManager.notify(&INodeObserver::poolChanged); } void InProcessNode::updateLastLocalBlockHeaderInfo() { Hash topBlockHash; uint32_t topBlockIndex; BlockTemplate block; Difficulty difficulty; try { topBlockHash = core.getTopBlockHash(); topBlockIndex = core.getTopBlockIndex(); block = core.getBlockByIndex(topBlockIndex); difficulty = core.getBlockDifficulty(topBlockIndex); } catch (const std::exception&) { return; } lastLocalBlockHeaderInfo.index = topBlockIndex; lastLocalBlockHeaderInfo.majorVersion = block.majorVersion; lastLocalBlockHeaderInfo.minorVersion = block.minorVersion; lastLocalBlockHeaderInfo.timestamp = block.timestamp; lastLocalBlockHeaderInfo.hash = topBlockHash; lastLocalBlockHeaderInfo.prevHash = block.previousBlockHash; lastLocalBlockHeaderInfo.nonce = block.nonce; lastLocalBlockHeaderInfo.isAlternative = false; lastLocalBlockHeaderInfo.depth = 0; lastLocalBlockHeaderInfo.difficulty = difficulty; lastLocalBlockHeaderInfo.reward = getBlockReward(block); } void InProcessNode::resetLastLocalBlockHeaderInfo() { lastLocalBlockHeaderInfo.index = 0; lastLocalBlockHeaderInfo.majorVersion = 0; lastLocalBlockHeaderInfo.minorVersion = 0; lastLocalBlockHeaderInfo.timestamp = 0; lastLocalBlockHeaderInfo.hash = CryptoNote::NULL_HASH; lastLocalBlockHeaderInfo.prevHash = CryptoNote::NULL_HASH; lastLocalBlockHeaderInfo.nonce = 0; lastLocalBlockHeaderInfo.isAlternative = false; lastLocalBlockHeaderInfo.depth = 0; lastLocalBlockHeaderInfo.difficulty = 0; lastLocalBlockHeaderInfo.reward = 0; } void InProcessNode::blockchainSynchronized(uint32_t topHeight) { observerManager.notify(&INodeObserver::blockchainSynchronized, topHeight); } void InProcessNode::queryBlocks(std::vector<:hash>&& knownBlockIds, uint64_t timestamp, std::vector& newBlocks, uint32_t& startHeight, const Callback& callback) { auto lock = std::unique_lock<:mutex>{mutex}; if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &newBlocks, &startHeight] () mutable { auto ec = doQueryBlocksLite(std::move(knownBlockIds), timestamp, newBlocks, startHeight); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doQueryBlocksLite(std::vector<:hash>&& knownBlockIds, uint64_t timestamp, std::vector& newBlocks, uint32_t& startHeight) { uint32_t currentHeight, fullOffset; std::vector<:blockshortinfo> 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, 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<:hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual, std::vector<:unique_ptr>>& newTxs, std::vector<:hash>& deletedTxIds, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &isBcActual, &newTxs, &deletedTxIds] () mutable { auto ec = doGetPoolSymmetricDifference(std::move(knownPoolTxIds), knownBlockId, isBcActual, newTxs, deletedTxIds); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetPoolSymmetricDifference(std::vector<:hash>&& knownPoolTxIds, Crypto::Hash knownBlockId, bool& isBcActual, std::vector<:unique_ptr>>& newTxs, std::vector<:hash>& deletedTxIds) { std::error_code ec; 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); } return ec; } void InProcessNode::getBlocks(const std::vector& blockHeights, std::vector<:vector>>& blocks, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &blocks] () { auto ec = doGetBlocks(blockHeights, blocks); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetBlocks(const std::vector& blockIndexes, std::vector<:vector>>& blocks) { try { auto topIndex = core.getTopBlockIndex(); for (auto index : blockIndexes) { if (index > topIndex) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } Crypto::Hash hash = core.getBlockHashByIndex(index); BlockDetails blockDetails = core.getBlockDetails(hash); std::vector blocksOnSameIndex; blocksOnSameIndex.push_back(std::move(blockDetails)); // Getting alternative blocks std::vector<:hash> alternativeBlocks = core.getAlternativeBlockHashesByIndex(index); for (const auto& alternativeBlockHash : alternativeBlocks) { BlockDetails alternativeBlockDetails = core.getBlockDetails(alternativeBlockHash); blocksOnSameIndex.push_back(std::move(alternativeBlockDetails)); } blocks.push_back(std::move(blocksOnSameIndex)); } } 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<:hash>& blockHashes, std::vector& blocks, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &blocks] () { auto ec = doGetBlocks(blockHashes, blocks); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetBlocks(const std::vector<:hash>& blockHashes, std::vector& blocks) { try { for (auto& hash : blockHashes) { if (!core.hasBlock(hash)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } BlockDetails blockDetails = core.getBlockDetails(hash); 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::getTransactions(const std::vector<:hash>& transactionHashes, std::vector& transactions, const Callback& callback) { std::unique_lock<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &transactions] () { auto ec = doGetTransactions(transactionHashes, transactions); executeInRemoteThread([callback, ec] () { callback(ec); }); }); } std::error_code InProcessNode::doGetTransactions(const std::vector<:hash>& transactionHashes, std::vector& transactions) { try { for (const auto& hash : transactionHashes) { if (!core.hasTransaction(hash)) { return make_error_code(CryptoNote::error::REQUEST_ERROR); } TransactionDetails transactionDetails = core.getTransactionDetails(hash); 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<:mutex> lock(mutex); if (state != INITIALIZED) { lock.unlock(); callback(make_error_code(CryptoNote::error::NOT_INITIALIZED)); return; } executeInDispatcherThread([=, &syncStatus] () { syncStatus = protocol.isSynchronized(); executeInRemoteThread([callback] () { callback({}); }); }); } } //namespace CryptoNote