Example #1
0
bool MergedMiner::mine(std::string address1, std::string wallet1, std::string address2, std::string wallet2, size_t threads) {
  epee::net_utils::http::http_simple_client httpClient1;
  epee::net_utils::http::http_simple_client httpClient2;
  Miner miner;
  BlockTemplate blockTemplate1;
  BlockTemplate blockTemplate2;
  cryptonote::block block1;
  cryptonote::block block2;
  cryptonote::difficulty_type difficulty1;
  cryptonote::difficulty_type difficulty2;
  std::future<bool> request1;
  std::future<bool> request2;
  std::future<bool> mining;
  crypto::hash hash;
  std::chrono::steady_clock::time_point time1;

  uint64_t prefix1;
  cryptonote::account_public_address walletAddress1;
  if (!get_account_address_from_str(prefix1, walletAddress1, wallet1)) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_messages.push("Failed to parse donor wallet address");
    return false;
  }

  uint64_t prefix2;
  cryptonote::account_public_address walletAddress2;
  if (!address2.empty() && !get_account_address_from_str(prefix2, walletAddress2, wallet2)) {
    std::lock_guard<std::mutex> lock(m_mutex);
    m_messages.push("Failed to parse acceptor wallet address");
    return false;
  }

  m_blockCount = 0;
  for (;;) {
    miner.getHashCount();

    if (m_stopped) {
      if (mining.valid()) {
        miner.stop();
        mining.wait();
      }

      return true;
    }

    request1 = std::async(std::launch::async, getBlockTemplate, &httpClient1, &address1, &wallet1, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate1);
    if (!address2.empty()) {
      request2 = std::async(std::launch::async, getBlockTemplate, &httpClient2, &address2, &wallet2, MERGE_MINING_TAG_RESERVED_SIZE, &blockTemplate2);
    }

    if (!request1.get()) {
      std::lock_guard<std::mutex> lock(m_mutex);
      m_messages.push("Failed to get donor block");
      continue;
    }

    if (!address2.empty()) {
      if (!request2.get()) {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_messages.push("Failed to get acceptor block");
        continue;
      }

      if (blockTemplate2.block.major_version != BLOCK_MAJOR_VERSION_2) {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_messages.push("Unsupported block version received from acceptor network, merged mining is not possible");
        if (mining.valid()) {
          miner.stop();
          mining.wait();
        }

        return false;
      }
    }

    if (mining.valid()) {
      miner.stop();
      if (mining.get()) {
        if (cryptonote::check_hash(hash, difficulty1)) {
          if (submitBlock(httpClient1, address1, block1)) {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_messages.push("Submitted donor block");
          } else {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_messages.push("Failed to submit donor block");
          }
        }

        if (!address2.empty() && cryptonote::check_hash(hash, difficulty2)) {
          if (!mergeBlocks(block1, block2)) {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_messages.push("Internal error");
            return false;
          }

          if (submitBlock(httpClient2, address2, block2)) {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_messages.push("Submitted acceptor block");
          } else {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_messages.push("Failed to submit acceptor block");
          }
        }
      }

      std::chrono::steady_clock::time_point time2 = std::chrono::steady_clock::now();
      std::ostringstream stream;
      stream << "Hashrate: " << miner.getHashCount() / std::chrono::duration_cast<std::chrono::duration<double>>(time2 - time1).count();
      std::lock_guard<std::mutex> lock(m_mutex);
      m_messages.push(stream.str());
      time1 = time2;

      miner.start();
    } else {
      time1 = std::chrono::steady_clock::now();
    }

    block1 = blockTemplate1.block;
    difficulty1 = blockTemplate1.difficulty;
    cryptonote::difficulty_type difficulty = difficulty1;
    if (!address2.empty()) {
      block2 = blockTemplate2.block;
      difficulty2 = blockTemplate2.difficulty;
      difficulty = std::min(difficulty, difficulty2);
      if (!fillExtra(block1, block2)) {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_messages.push("Internal error");
        return false;
      }
    }

    mining = std::async(std::launch::async, &Miner::findNonce, &miner, &block1, blockTemplate1.height, difficulty, threads, &hash);
    for (size_t i = 0; i < 50; ++i) {
      if (m_stopped || mining.wait_for(std::chrono::milliseconds(100)) == std::future_status::ready) {
        break;
      }
    }
  }
}