mirror of
https://github.com/dogecoin/dogecoin.git
synced 2026-03-16 08:22:31 +00:00
387 lines
11 KiB
C++
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);
|
|
}
|