dogecoin/src/qt/miningpage.cpp

387 lines
11 KiB
C++

#include "miningpage.h"
#include "ui_miningpage.h"
MiningPage::MiningPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::MiningPage)
{
ui->setupUi(this);
setFixedSize(400, 420);
minerActive = false;
minerProcess = new QProcess(this);
minerProcess->setProcessChannelMode(QProcess::MergedChannels);
readTimer = new QTimer(this);
acceptedShares = 0;
rejectedShares = 0;
roundAcceptedShares = 0;
roundRejectedShares = 0;
initThreads = 0;
connect(readTimer, SIGNAL(timeout()), this, SLOT(readProcessOutput()));
connect(ui->startButton, SIGNAL(pressed()), this, SLOT(startPressed()));
connect(ui->typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(typeChanged(int)));
connect(ui->debugCheckBox, SIGNAL(toggled(bool)), this, SLOT(debugToggled(bool)));
connect(minerProcess, SIGNAL(started()), this, SLOT(minerStarted()));
connect(minerProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(minerError(QProcess::ProcessError)));
connect(minerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(minerFinished()));
connect(minerProcess, SIGNAL(readyRead()), this, SLOT(readProcessOutput()));
}
MiningPage::~MiningPage()
{
minerProcess->kill();
delete ui;
}
void MiningPage::setModel(ClientModel *model)
{
this->model = model;
loadSettings();
bool pool = model->getMiningType() == ClientModel::PoolMining;
ui->threadsBox->setValue(model->getMiningThreads());
ui->typeBox->setCurrentIndex(pool ? 1 : 0);
// if (model->getMiningStarted())
// startPressed();
}
void MiningPage::startPressed()
{
initThreads = ui->threadsBox->value();
if (minerActive == false)
{
saveSettings();
if (getMiningType() == ClientModel::SoloMining)
minerStarted();
else
startPoolMining();
}
else
{
if (getMiningType() == ClientModel::SoloMining)
minerFinished();
else
stopPoolMining();
}
}
void MiningPage::startPoolMining()
{
QStringList args;
QString url = ui->serverLine->text();
if (!url.contains("://")) // Any protocol is accepted
url.prepend("http://");
QString urlLine = QString("%1:%2").arg(url, ui->portLine->text());
QString userpassLine = QString("%1:%2").arg(ui->usernameLine->text(), ui->passwordLine->text());
args << "--algo" << "scrypt";
args << "--scantime" << ui->scantimeBox->text().toAscii();
args << "--url" << urlLine.toAscii();
args << "--userpass" << userpassLine.toAscii();
args << "--threads" << ui->threadsBox->text().toAscii();
args << "--retries" << "-1"; // Retry forever.
args << "-P"; // This is needed for this to work correctly on Windows. Extra protocol dump helps flush the buffer quicker.
threadSpeed.clear();
acceptedShares = 0;
rejectedShares = 0;
roundAcceptedShares = 0;
roundRejectedShares = 0;
// If minerd is in current path, then use that. Otherwise, assume minerd is in the path somewhere.
QString program = QDir::current().filePath("minerd");
if (!QFile::exists(program))
program = "minerd";
if (ui->debugCheckBox->isChecked())
ui->list->addItem(args.join(" ").prepend(" ").prepend(program));
ui->mineSpeedLabel->setText("Speed: N/A");
ui->shareCount->setText("Accepted: 0 - Rejected: 0");
minerProcess->start(program,args);
minerProcess->waitForStarted(-1);
readTimer->start(500);
}
void MiningPage::stopPoolMining()
{
ui->mineSpeedLabel->setText("");
minerProcess->kill();
readTimer->stop();
}
void MiningPage::saveSettings()
{
model->setMiningDebug(ui->debugCheckBox->isChecked());
model->setMiningScanTime(ui->scantimeBox->value());
model->setMiningServer(ui->serverLine->text());
model->setMiningPort(ui->portLine->text());
model->setMiningUsername(ui->usernameLine->text());
model->setMiningPassword(ui->passwordLine->text());
}
void MiningPage::loadSettings()
{
ui->debugCheckBox->setChecked(model->getMiningDebug());
ui->scantimeBox->setValue(model->getMiningScanTime());
ui->serverLine->setText(model->getMiningServer());
ui->portLine->setText(model->getMiningPort());
ui->usernameLine->setText(model->getMiningUsername());
ui->passwordLine->setText(model->getMiningPassword());
}
void MiningPage::readProcessOutput()
{
QByteArray output;
minerProcess->reset();
output = minerProcess->readAll();
QString outputString(output);
if (!outputString.isEmpty())
{
QStringList list = outputString.split("\n", QString::SkipEmptyParts);
int i;
for (i=0; i<list.size(); i++)
{
QString line = list.at(i);
// Ignore protocol dump
if (!line.startsWith("[") || line.contains("JSON protocol") || line.contains("HTTP hdr"))
continue;
if (ui->debugCheckBox->isChecked())
{
ui->list->addItem(line.trimmed());
ui->list->scrollToBottom();
}
if (line.contains("(yay!!!)"))
reportToList("Share accepted", SHARE_SUCCESS, getTime(line));
else if (line.contains("(booooo)"))
reportToList("Share rejected", SHARE_FAIL, getTime(line));
else if (line.contains("LONGPOLL detected new block"))
reportToList("LONGPOLL detected a new block", LONGPOLL, getTime(line));
else if (line.contains("Supported options:"))
reportToList("Miner didn't start properly. Try checking your settings.", ERROR, NULL);
else if (line.contains("The requested URL returned error: 403"))
reportToList("Couldn't connect. Please check your username and password.", ERROR, NULL);
else if (line.contains("HTTP request failed"))
reportToList("Couldn't connect. Please check pool server and port.", ERROR, NULL);
else if (line.contains("JSON-RPC call failed"))
reportToList("Couldn't communicate with server. Retrying in 30 seconds.", ERROR, NULL);
else if (line.contains("thread ") && line.contains("khash/s"))
{
QString threadIDstr = line.at(line.indexOf("thread ")+7);
int threadID = threadIDstr.toInt();
int threadSpeedindx = line.indexOf(",");
QString threadSpeedstr = line.mid(threadSpeedindx);
threadSpeedstr.chop(8);
threadSpeedstr.remove(", ");
threadSpeedstr.remove(" ");
threadSpeedstr.remove('\n');
double speed=0;
speed = threadSpeedstr.toDouble();
threadSpeed[threadID] = speed;
updateSpeed();
}
}
}
}
void MiningPage::minerError(QProcess::ProcessError error)
{
if (error == QProcess::FailedToStart)
{
reportToList("No dig such fail", ERROR, NULL);
}
}
void MiningPage::minerFinished()
{
if (getMiningType() == ClientModel::SoloMining)
reportToList("Solo dig stop", ERROR, NULL);
else
reportToList("Dig exit", ERROR, NULL);
ui->list->addItem("");
minerActive = false;
resetMiningButton();
model->setMining(getMiningType(), false, initThreads, 0);
}
void MiningPage::minerStarted()
{
if (!minerActive)
if (getMiningType() == ClientModel::SoloMining)
reportToList("Solo dig start", ERROR, NULL);
else
reportToList("Dig start", STARTED, NULL);
minerActive = true;
resetMiningButton();
model->setMining(getMiningType(), true, initThreads, 0);
}
void MiningPage::updateSpeed()
{
double totalSpeed=0;
int totalThreads=0;
QMapIterator<int, double> iter(threadSpeed);
while(iter.hasNext())
{
iter.next();
totalSpeed += iter.value();
totalThreads++;
}
// If all threads haven't reported the hash speed yet, make an assumption
if (totalThreads != initThreads)
{
totalSpeed = (totalSpeed/totalThreads)*initThreads;
}
QString speedString = QString("%1").arg(totalSpeed);
QString threadsString = QString("%1").arg(initThreads);
QString acceptedString = QString("%1").arg(acceptedShares);
QString rejectedString = QString("%1").arg(rejectedShares);
QString roundAcceptedString = QString("%1").arg(roundAcceptedShares);
QString roundRejectedString = QString("%1").arg(roundRejectedShares);
if (totalThreads == initThreads)
ui->mineSpeedLabel->setText(QString("Speed: %1 khash/sec - %2 thread(s)").arg(speedString, threadsString));
else
ui->mineSpeedLabel->setText(QString("Speed: ~%1 khash/sec - %2 thread(s)").arg(speedString, threadsString));
ui->shareCount->setText(QString("Accepted: %1 (%3) - Rejected: %2 (%4)").arg(acceptedString, rejectedString, roundAcceptedString, roundRejectedString));
model->setMining(getMiningType(), true, initThreads, totalSpeed*1000);
}
void MiningPage::reportToList(QString msg, int type, QString time)
{
QString message;
if (time == NULL)
message = QString("[%1] - %2").arg(QTime::currentTime().toString(), msg);
else
message = QString("[%1] - %2").arg(time, msg);
switch(type)
{
case SHARE_SUCCESS:
acceptedShares++;
roundAcceptedShares++;
updateSpeed();
break;
case SHARE_FAIL:
rejectedShares++;
roundRejectedShares++;
updateSpeed();
break;
case LONGPOLL:
roundAcceptedShares = 0;
roundRejectedShares = 0;
break;
default:
break;
}
ui->list->addItem(message);
ui->list->scrollToBottom();
}
// Function for fetching the time
QString MiningPage::getTime(QString time)
{
if (time.contains("["))
{
time.resize(21);
time.remove("[");
time.remove("]");
time.remove(0,11);
return time;
}
else
return NULL;
}
void MiningPage::enableMiningControls(bool enable)
{
ui->typeBox->setEnabled(enable);
ui->threadsBox->setEnabled(enable);
ui->scantimeBox->setEnabled(enable);
ui->serverLine->setEnabled(enable);
ui->portLine->setEnabled(enable);
ui->usernameLine->setEnabled(enable);
ui->passwordLine->setEnabled(enable);
}
void MiningPage::enablePoolMiningControls(bool enable)
{
ui->scantimeBox->setEnabled(enable);
ui->serverLine->setEnabled(enable);
ui->portLine->setEnabled(enable);
ui->usernameLine->setEnabled(enable);
ui->passwordLine->setEnabled(enable);
}
ClientModel::MiningType MiningPage::getMiningType()
{
if (ui->typeBox->currentIndex() == 0) // Solo Mining
{
return ClientModel::SoloMining;
}
else if (ui->typeBox->currentIndex() == 1) // Pool Mining
{
return ClientModel::PoolMining;
}
return ClientModel::SoloMining;
}
void MiningPage::typeChanged(int index)
{
if (index == 0) // Solo Mining
{
enablePoolMiningControls(false);
}
else if (index == 1) // Pool Mining
{
enablePoolMiningControls(true);
}
}
void MiningPage::debugToggled(bool checked)
{
model->setMiningDebug(checked);
}
void MiningPage::resetMiningButton()
{
ui->startButton->setText(minerActive ? "Stop Dig" : "Start Dig");
enableMiningControls(!minerActive);
}