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::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;
            }
          }
        }
      }
    }
  }
}