Exemplo n.º 1
0
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::stop() {
  setFutureState(State::stopped);

  // wait for previous processing to end
  if (workingThread.get() != nullptr && workingThread->joinable()) {
    workingThread->join();
  }

  workingThread.reset();
}
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));
  }
}
void BlockchainSynchronizer::poolChanged() {
  setFutureState(State::poolSync);
}
void BlockchainSynchronizer::lastKnownBlockHeightUpdated(uint32_t height) {
  setFutureState(State::blockchainSync);
}
Exemplo n.º 7
0
void BlockchainSynchronizer::localBlockchainUpdated(uint32_t /*height*/) {
  setFutureState(State::blockchainSync);
}