danicoin/src/Miner/Miner.cpp
2016-01-18 15:33:29 +00:00

145 lines
3.9 KiB
C++

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "Miner.h"
#include <functional>
#include "crypto/crypto.h"
#include "CryptoNoteCore/CryptoNoteFormatUtils.h"
#include <System/InterruptedException.h>
namespace CryptoNote {
Miner::Miner(System::Dispatcher& dispatcher, Logging::ILogger& logger) :
m_dispatcher(dispatcher),
m_miningStopped(dispatcher),
m_state(MiningState::MINING_STOPPED),
m_logger(logger, "Miner") {
}
Miner::~Miner() {
assert(m_state != MiningState::MINING_IN_PROGRESS);
}
Block Miner::mine(const BlockMiningParameters& blockMiningParameters, size_t threadCount) {
if (threadCount == 0) {
throw std::runtime_error("Miner requires at least one thread");
}
if (m_state == MiningState::MINING_IN_PROGRESS) {
throw std::runtime_error("Mining is already in progress");
}
m_state = MiningState::MINING_IN_PROGRESS;
m_miningStopped.clear();
runWorkers(blockMiningParameters, threadCount);
assert(m_state != MiningState::MINING_IN_PROGRESS);
if (m_state == MiningState::MINING_STOPPED) {
m_logger(Logging::DEBUGGING) << "Mining has been stopped";
throw System::InterruptedException();
}
assert(m_state == MiningState::BLOCK_FOUND);
return m_block;
}
void Miner::stop() {
MiningState state = MiningState::MINING_IN_PROGRESS;
if (m_state.compare_exchange_weak(state, MiningState::MINING_STOPPED)) {
m_miningStopped.wait();
m_miningStopped.clear();
}
}
void Miner::runWorkers(BlockMiningParameters blockMiningParameters, size_t threadCount) {
assert(threadCount > 0);
m_logger(Logging::INFO) << "Starting mining for difficulty " << blockMiningParameters.difficulty;
try {
blockMiningParameters.blockTemplate.nonce = Crypto::rand<uint32_t>();
for (size_t i = 0; i < threadCount; ++i) {
m_workers.emplace_back(std::unique_ptr<System::RemoteContext<void>> (
new System::RemoteContext<void>(m_dispatcher, std::bind(&Miner::workerFunc, this, blockMiningParameters.blockTemplate, blockMiningParameters.difficulty, threadCount)))
);
blockMiningParameters.blockTemplate.nonce++;
}
m_workers.clear();
} catch (std::exception& e) {
m_logger(Logging::ERROR) << "Error occured during mining: " << e.what();
m_state = MiningState::MINING_STOPPED;
}
m_miningStopped.set();
}
void Miner::workerFunc(const Block& blockTemplate, difficulty_type difficulty, uint32_t nonceStep) {
try {
Block block = blockTemplate;
Crypto::cn_context cryptoContext;
while (m_state == MiningState::MINING_IN_PROGRESS) {
Crypto::Hash hash;
if (!get_block_longhash(cryptoContext, block, hash)) {
//error occured
m_logger(Logging::DEBUGGING) << "calculating long hash error occured";
m_state = MiningState::MINING_STOPPED;
return;
}
if (check_hash(hash, difficulty)) {
m_logger(Logging::INFO) << "Found block for difficulty " << difficulty;
if (!setStateBlockFound()) {
m_logger(Logging::DEBUGGING) << "block is already found or mining stopped";
return;
}
m_block = block;
return;
}
block.nonce += nonceStep;
}
} catch (std::exception& e) {
m_logger(Logging::ERROR) << "Miner got error: " << e.what();
m_state = MiningState::MINING_STOPPED;
}
}
bool Miner::setStateBlockFound() {
auto state = m_state.load();
for (;;) {
switch (state) {
case MiningState::BLOCK_FOUND:
return false;
case MiningState::MINING_IN_PROGRESS:
if (m_state.compare_exchange_weak(state, MiningState::BLOCK_FOUND)) {
return true;
}
break;
case MiningState::MINING_STOPPED:
return false;
default:
assert(false);
return false;
}
}
}
} //namespace CryptoNote