void BlockchainSynchronizer::startBlockchainSync() { GetBlocksResponse response; GetBlocksRequest req = getCommonHistory(); try { if (!req.knownBlocks.empty()) { auto queryBlocksCompleted = std::promise<std::error_code>(); auto queryBlocksWaitFuture = queryBlocksCompleted.get_future(); m_node.queryBlocks( std::move(req.knownBlocks), req.syncStart.timestamp, response.newBlocks, response.startHeight, [&queryBlocksCompleted](std::error_code ec) { auto detachedPromise = std::move(queryBlocksCompleted); detachedPromise.set_value(ec); }); std::error_code ec = queryBlocksWaitFuture.get(); if (ec) { setFutureStateIf(State::idle, [this] { return m_futureState != State::stopped; }); m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, ec); } else { processBlocks(response); } } } catch (std::exception&) { setFutureStateIf(State::idle, [this] { return m_futureState != State::stopped; }); m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, std::make_error_code(std::errc::invalid_argument)); } }
void BlockchainSynchronizer::startPoolSync() { std::unordered_set<Crypto::Hash> unionPoolHistory; std::unordered_set<Crypto::Hash> intersectedPoolHistory; getPoolUnionAndIntersection(unionPoolHistory, intersectedPoolHistory); GetPoolRequest unionRequest; unionRequest.knownTxIds.assign(unionPoolHistory.begin(), unionPoolHistory.end()); unionRequest.lastKnownBlock = lastBlockId; GetPoolResponse unionResponse; unionResponse.isLastKnownBlockActual = false; std::error_code ec = getPoolSymmetricDifferenceSync(std::move(unionRequest), unionResponse); if (ec) { setFutureStateIf(State::idle, [this] { return m_futureState != State::stopped; }); m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, ec); } else { //get union ok if (!unionResponse.isLastKnownBlockActual) { //bc outdated setFutureState(State::blockchainSync); } else { if (unionPoolHistory == intersectedPoolHistory) { //usual case, start pool processing m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, processPoolTxs(unionResponse)); } else { GetPoolRequest intersectionRequest; intersectionRequest.knownTxIds.assign(intersectedPoolHistory.begin(), intersectedPoolHistory.end()); intersectionRequest.lastKnownBlock = lastBlockId; GetPoolResponse intersectionResponse; intersectionResponse.isLastKnownBlockActual = false; std::error_code ec2 = getPoolSymmetricDifferenceSync(std::move(intersectionRequest), intersectionResponse); if (ec2) { setFutureStateIf(State::idle, [this] { return m_futureState != State::stopped; }); m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, ec2); } else { //get intersection ok if (!intersectionResponse.isLastKnownBlockActual) { //bc outdated setFutureState(State::blockchainSync); } else { intersectionResponse.deletedTxIds.assign(unionResponse.deletedTxIds.begin(), unionResponse.deletedTxIds.end()); std::error_code ec3 = processPoolTxs(intersectionResponse); //notify about error, or success m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, ec3); } } } } } }
void BlockchainSynchronizer::start() { if (m_consumers.empty()) { throw std::runtime_error("Can't start, because BlockchainSynchronizer has no consumers"); } if (!setFutureStateIf(State::blockchainSync, [this] { return m_currentState == State::stopped && m_futureState == State::stopped; })) { throw std::runtime_error("BlockchainSynchronizer already started"); } workingThread.reset(new std::thread([this] { workingProcedure(); })); }
void BlockchainSynchronizer::startBlockchainSync() { GetBlocksResponse response; GetBlocksRequest req = getCommonHistory(); try { if (!req.knownBlocks.empty()) { asyncOperationCompleted = std::promise<std::error_code>(); asyncOperationWaitFuture = asyncOperationCompleted.get_future(); m_node.queryBlocks (std::move(req.knownBlocks), req.syncStart.timestamp, response.newBlocks, response.startHeight, std::bind(&BlockchainSynchronizer::onGetBlocksCompleted, this, std::placeholders::_1)); std::error_code ec = asyncOperationWaitFuture.get(); if (ec) { setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState))); m_observerManager.notify(&IBlockchainSynchronizerObserver::synchronizationCompleted, ec); } else { processBlocks(response); } } } catch (std::exception& e) { std::cout << e.what() << std::endl; setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState))); m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, std::make_error_code(std::errc::invalid_argument)); } }
void BlockchainSynchronizer::start() { if (m_consumers.empty()) { throw std::runtime_error("Can't start, because BlockchainSynchronizer has no consumers"); } if (!setFutureStateIf(State::blockchainSync, std::bind( [](State currentState, State futureState) -> bool { return currentState == State::stopped && futureState == State::stopped; }, std::ref(m_currentState), std::ref(m_futureState)))) { throw std::runtime_error("BlockchainSynchronizer already started"); } shouldSyncConsumersPool = true; workingThread.reset(new std::thread([this] {this->workingProcedure(); })); }
void BlockchainSynchronizer::startPoolSync() { GetPoolResponse unionResponse; GetPoolRequest unionRequest = getUnionPoolHistory(); asyncOperationCompleted = std::promise<std::error_code>(); asyncOperationWaitFuture = asyncOperationCompleted.get_future(); unionResponse.isLastKnownBlockActual = false; m_node.getPoolSymmetricDifference(std::move(unionRequest.knownTxIds), std::move(unionRequest.lastKnownBlock), unionResponse.isLastKnownBlockActual, unionResponse.newTxs, unionResponse.deletedTxIds, std::bind(&BlockchainSynchronizer::onGetPoolChanges, this, std::placeholders::_1)); std::error_code ec = asyncOperationWaitFuture.get(); if (ec) { setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState))); m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, ec); } else { //get union ok if (!unionResponse.isLastKnownBlockActual) { //bc outdated setFutureState(State::blockchainSync); } else { if (!shouldSyncConsumersPool) { //usual case, start pool processing m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, processPoolTxs(unionResponse)); } else {// first launch, we should sync consumers' pools, so let's ask for intersection GetPoolResponse intersectionResponse; GetPoolRequest intersectionRequest = getIntersectedPoolHistory(); asyncOperationCompleted = std::promise<std::error_code>(); asyncOperationWaitFuture = asyncOperationCompleted.get_future(); intersectionResponse.isLastKnownBlockActual = false; m_node.getPoolSymmetricDifference(std::move(intersectionRequest.knownTxIds), std::move(intersectionRequest.lastKnownBlock), intersectionResponse.isLastKnownBlockActual, intersectionResponse.newTxs, intersectionResponse.deletedTxIds, std::bind(&BlockchainSynchronizer::onGetPoolChanges, this, std::placeholders::_1)); std::error_code ec2 = asyncOperationWaitFuture.get(); if (ec2) { setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState))); m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, ec2); } else { //get intersection ok if (!intersectionResponse.isLastKnownBlockActual) { //bc outdated setFutureState(State::blockchainSync); } else { intersectionResponse.deletedTxIds.assign(unionResponse.deletedTxIds.begin(), unionResponse.deletedTxIds.end()); std::error_code ec3 = processPoolTxs(intersectionResponse); //notify about error, or success m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, ec3); if (!ec3) { shouldSyncConsumersPool = false; } } } } } } }
void BlockchainSynchronizer::processBlocks(GetBlocksResponse& response) { uint32_t newHeight = response.startHeight + static_cast<uint32_t>(response.newBlocks.size()); BlockchainInterval interval; interval.startHeight = response.startHeight; std::vector<CompleteBlock> blocks; for (auto& block : response.newBlocks) { if (checkIfShouldStop()) { break; } CompleteBlock completeBlock; completeBlock.blockHash = block.blockHash; interval.blocks.push_back(completeBlock.blockHash); if (block.hasBlock) { completeBlock.block = std::move(block.block); completeBlock.transactions.push_back(createTransactionPrefix(completeBlock.block->baseTransaction)); try { for (const auto& txShortInfo : block.txsShortInfo) { completeBlock.transactions.push_back(createTransactionPrefix(txShortInfo.txPrefix, reinterpret_cast<const Hash&>(txShortInfo.txId))); } } catch (std::exception&) { setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState))); m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, std::make_error_code(std::errc::invalid_argument)); return; } } blocks.push_back(std::move(completeBlock)); } if (!checkIfShouldStop()) { response.newBlocks.clear(); std::unique_lock<std::mutex> lk(m_consumersMutex); auto result = updateConsumers(interval, blocks); lk.unlock(); switch (result) { case UpdateConsumersResult::errorOccured: if (setFutureStateIf(State::idle, std::bind( [](State futureState) -> bool { return futureState != State::stopped; }, std::ref(m_futureState)))) { m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, std::make_error_code(std::errc::invalid_argument)); } break; case UpdateConsumersResult::nothingChanged: if (m_node.getLastKnownBlockHeight() != m_node.getLastLocalBlockHeight()) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else { break; } case UpdateConsumersResult::addedNewBlocks: setFutureState(State::blockchainSync); m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationProgressUpdated, newHeight, std::max(m_node.getKnownBlockCount(), m_node.getLocalBlockCount())); break; } if (!blocks.empty()) { lastBlockId = blocks.back().blockHash; } } if (checkIfShouldStop()) { //Sic! m_observerManager.notify( &IBlockchainSynchronizerObserver::synchronizationCompleted, std::make_error_code(std::errc::interrupted)); } }
bool BlockchainSynchronizer::setFutureState(State s) { return setFutureStateIf(s, std::bind( [](State futureState, State s) -> bool { return s > futureState; }, std::ref(m_futureState), s)); }
bool BlockchainSynchronizer::setFutureState(State s) { return setFutureStateIf(s, [this, s] { return s > m_futureState; }); }