Browse Source

Improved ShareLimiter

master
Intel 10 years ago
parent
commit
bd229a0dac
  1. 4
      src/server/poolserver/Main.cpp
  2. 60
      src/server/poolserver/Stratum/Client.cpp
  3. 14
      src/server/poolserver/Stratum/Client.h
  4. 6
      src/server/poolserver/Stratum/Job.h
  5. 16
      src/server/poolserver/Stratum/ShareLimiter.cpp
  6. 9
      src/server/poolserver/Stratum/ShareLimiter.h

4
src/server/poolserver/Main.cpp

@ -48,9 +48,11 @@ bool InitConfig(int argc, char *argv[]) @@ -48,9 +48,11 @@ bool InitConfig(int argc, char *argv[])
("StratumPort,sp", boost::program_options::value<uint16_t>()->default_value(3333), "Stratum server port")
("StratumBlockCheckTime", boost::program_options::value<uint32>()->default_value(2000), "Time between block checks in ms")
("RetargetInterval", boost::program_options::value<uint32>()->default_value(20), "Time between difficulty checks in seconds")
("RetargetSharesThreashold", boost::program_options::value<uint32>()->default_value(20), "Number of shares in retarget interval to trigger a difficulty check")
("RetargetTimeBuffer", boost::program_options::value<uint32>()->default_value(60*5), "Buffer of shares to keep (in seconds)")
("RetargetTimePerShare", boost::program_options::value<double>()->default_value(10), "Target in seconds between shares")
("RetargetTimePerShare", boost::program_options::value<double>()->default_value(4), "Target in seconds between shares")
("RetargetVariance", boost::program_options::value<uint32>()->default_value(40), "Maximum allowed variance in percent before difficulty change")
("RetargetStartingDiff", boost::program_options::value<uint32>()->default_value(2), "Difficulty at which new miner starts")
("RetargetMinDiff", boost::program_options::value<uint32>()->default_value(1), "Minimum difficulty (also starting difficulty)")
("RetargetMaxDiff", boost::program_options::value<uint32>()->default_value(1000000), "Maximum difficulty we can reach")
;

60
src/server/poolserver/Stratum/Client.cpp

@ -37,9 +37,9 @@ namespace Stratum @@ -37,9 +37,9 @@ namespace Stratum
void Client::SendJob(bool clean)
{
if (clean)
_jobs.clear();
CleanJobs();
Job job = GetJob();
Job* job = GetJob();
uint32 jobid = _jobid++;
_jobs[jobid] = job;
@ -51,14 +51,14 @@ namespace Stratum @@ -51,14 +51,14 @@ namespace Stratum
JSON merkle_branch(JSON_ARRAY);
uint32 j = 0;
for (uint32 size = job.block->tx.size(); size > 1; size = (size+1)/2)
for (uint32 size = job->block->tx.size(); size > 1; size = (size+1)/2)
{
merkle_branch.Add(Util::BinToASCII(job.block->merkleTree[j+1]));
merkle_branch.Add(Util::BinToASCII(job->block->merkleTree[j+1]));
j += size;
}
// Reverse prev block hash every 4 bytes... Makes a lot of sense...
ByteBuffer prevhashbuf(Util::Reverse(job.block->prevBlockHash));
ByteBuffer prevhashbuf(Util::Reverse(job->block->prevBlockHash));
std::vector<uint32> prevhash(8);
prevhashbuf >> prevhash[7] >> prevhash[6] >> prevhash[5] >> prevhash[4] >> prevhash[3] >> prevhash[2] >> prevhash[1] >> prevhash[0];
ByteBuffer prevhashfixed;
@ -67,12 +67,12 @@ namespace Stratum @@ -67,12 +67,12 @@ namespace Stratum
JSON params;
params.Add(jobss.str());
params.Add(Util::BinToASCII(prevhashfixed.Binary()));
params.Add(Util::BinToASCII(job.coinbase1));
params.Add(Util::BinToASCII(job.coinbase2));
params.Add(Util::BinToASCII(job->coinbase1));
params.Add(Util::BinToASCII(job->coinbase2));
params.Add(merkle_branch);
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job.block->version).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job.block->bits).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job.block->time).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job->block->version).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job->block->bits).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job->block->time).Binary())));
params.Add(clean);
JSON msg;
@ -122,10 +122,10 @@ namespace Stratum @@ -122,10 +122,10 @@ namespace Stratum
}
// Get job
Job& job = _jobs[jobid];
Job* job = _jobs[jobid];
// Share limiter
if (!_shareLimiter.Submit(job.diff)) {
if (!_shareLimiter.Submit(job->diff)) {
JSON response;
response["id"] = msg["id"];
response["result"];
@ -183,9 +183,9 @@ namespace Stratum @@ -183,9 +183,9 @@ namespace Stratum
sLog.Debug(LOG_STRATUM, "Job::SubmitShare: Nonce: %s, Extranonce: %s, Share: %u", Util::BinToASCII(noncebuf.Binary()).c_str(), Util::BinToASCII(extranonce2).c_str(), share);
if (!job.SubmitShare(share)) {
if (!job->SubmitShare(share)) {
sLog.Warn(LOG_STRATUM, "%s: Duplicate share", username.c_str());
DataMgr::Instance()->Push(Share(_ip, username, false, "Duplicate share", Util::Date(), job.diff));
DataMgr::Instance()->Push(Share(_ip, username, false, "Duplicate share", Util::Date(), job->diff));
_shareLimiter.LogBad();
JSON response;
@ -199,7 +199,7 @@ namespace Stratum @@ -199,7 +199,7 @@ namespace Stratum
}
// Copy block we are working on
Bitcoin::Block block = *job.block;
Bitcoin::Block block = *job->block;
// Start assembling the block
timebuf >> block.time;
@ -208,7 +208,7 @@ namespace Stratum @@ -208,7 +208,7 @@ namespace Stratum
// Assemble coinbase
Bitcoin::Transaction coinbasetx;
ByteBuffer coinbasebuf;
coinbasebuf << job.coinbase1 << _extranonce << extranonce2 << job.coinbase2;
coinbasebuf << job->coinbase1 << _extranonce << extranonce2 << job->coinbase2;
coinbasebuf >> coinbasetx;
// Set coinbase tx
@ -224,9 +224,9 @@ namespace Stratum @@ -224,9 +224,9 @@ namespace Stratum
BigInt target(Util::BinToASCII(Util::Reverse(hash)), 16);
// Check if difficulty meets job diff
if (target > job.jobTarget) {
if (target > job->jobTarget) {
sLog.Warn(LOG_STRATUM, "%s: Share above target", username.c_str());
DataMgr::Instance()->Push(Share(_ip, username, false, "Share above target", Util::Date(), job.diff));
DataMgr::Instance()->Push(Share(_ip, username, false, "Share above target", Util::Date(), job->diff));
_shareLimiter.LogBad();
JSON response;
@ -240,11 +240,11 @@ namespace Stratum @@ -240,11 +240,11 @@ namespace Stratum
}
// Check if block meets criteria
if (target <= job.blockTarget) {
if (target <= job->blockTarget) {
sLog.Info(LOG_STRATUM, "We have found a block candidate!");
// copy job diff because job will be deleted after submiting share by block template update
uint64 jobDiff = job.diff;
uint64 jobDiff = job->diff;
if (_server->SubmitBlock(block)) {
std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, `time`, `difficulty`) VALUES ");
@ -259,7 +259,7 @@ namespace Stratum @@ -259,7 +259,7 @@ namespace Stratum
return;
}
} else {
DataMgr::Instance()->Push(Share(_ip, username, true, "", Util::Date(), job.diff));
DataMgr::Instance()->Push(Share(_ip, username, true, "", Util::Date(), job->diff));
JSON response;
response["id"] = msg["id"];
@ -330,17 +330,17 @@ namespace Stratum @@ -330,17 +330,17 @@ namespace Stratum
}
}
Job Client::GetJob()
Job* Client::GetJob()
{
Job job;
job.block = _server->GetWork();
job.diff = _diff;
job.jobTarget = Bitcoin::DiffToTarget(job.diff);
job.blockTarget = Bitcoin::TargetFromBits(job.block->bits);
Job* job = new Job();
job->block = _server->GetWork();
job->diff = _diff;
job->jobTarget = Bitcoin::DiffToTarget(job->diff);
job->blockTarget = Bitcoin::TargetFromBits(job->block->bits);
// Serialize transaction
ByteBuffer coinbasebuf;
coinbasebuf << job.block->tx[0];
coinbasebuf << job->block->tx[0];
BinaryData coinbase = coinbasebuf.Binary();
// Split coinbase
@ -350,8 +350,8 @@ namespace Stratum @@ -350,8 +350,8 @@ namespace Stratum
// tx.script (varint) - 2 bytes
// tx.script (block height) - 4 bytes
uint32 cbsplit = 4 + 32 + 4 + 2 + 4;
job.coinbase1 = BinaryData(coinbase.begin(), coinbase.begin() + cbsplit);
job.coinbase2 = BinaryData(coinbase.begin() + cbsplit + 8, coinbase.end()); // plus extranonce size
job->coinbase1 = BinaryData(coinbase.begin(), coinbase.begin() + cbsplit);
job->coinbase2 = BinaryData(coinbase.begin() + cbsplit + 8, coinbase.end()); // plus extranonce size
return job;
}

14
src/server/poolserver/Stratum/Client.h

@ -27,12 +27,13 @@ namespace Stratum @@ -27,12 +27,13 @@ namespace Stratum
public:
Client(Server* server, asio::io_service& io_service, uint64 id) : _io_service(io_service), _server(server), _socket(io_service), _ioStrand(io_service), _id(id), _subscribed(false), _jobid(0), _shareLimiter(this)
{
_diff = sConfig.Get<uint32>("RetargetMinDiff");
_diff = sConfig.Get<uint32>("RetargetStartingDiff");
_minDiff = sConfig.Get<uint32>("RetargetMinDiff");
}
~Client()
{
CleanJobs();
sLog.Info(LOG_STRATUM, "%u: I'm going out! Cya!", _ip);
}
@ -89,7 +90,14 @@ namespace Stratum @@ -89,7 +90,14 @@ namespace Stratum
}
// Gets new job from the server
Job GetJob();
Job* GetJob();
void CleanJobs()
{
for (std::map<uint64, Job*>::iterator it = _jobs.begin(); it != _jobs.end(); ++it)
delete it->second;
_jobs.clear();
}
// Worker difficulty
uint64 GetDifficulty()
@ -177,7 +185,7 @@ namespace Stratum @@ -177,7 +185,7 @@ namespace Stratum
// Jobs
bool _subscribed;
uint32 _extranonce;
std::map<uint64, Job> _jobs;
std::map<uint64, Job*> _jobs;
uint32 _jobid;
// Share limiting

6
src/server/poolserver/Stratum/Job.h

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
#include "Util.h"
#include "BigNum.h"
#include <set>
#include <boost/thread.hpp>
namespace Stratum
{
@ -24,6 +25,8 @@ namespace Stratum @@ -24,6 +25,8 @@ namespace Stratum
// Returns false if the same share already exists
bool SubmitShare(uint64 share)
{
boost::unique_lock<boost::mutex> guard(_mtx);
std::set<uint64>::iterator it = shares.find(share);
if (it == shares.end()) {
shares.insert(share);
@ -31,6 +34,9 @@ namespace Stratum @@ -31,6 +34,9 @@ namespace Stratum
} else
return false;
}
private:
boost::mutex _mtx;
};
}

16
src/server/poolserver/Stratum/ShareLimiter.cpp

@ -12,14 +12,16 @@ namespace Stratum @@ -12,14 +12,16 @@ namespace Stratum
++_totalShares;
uint64 curTime = Util::Date();
uint64 sinceLast = curTime - _lastRetarget;
uint64 timeSinceRetarget = curTime - _lastRetargetTime;
uint64 sharesSinceRetarget = _totalShares - _lastRetargetShares;
_shares.push_back(ShareLimiterRecord(diff, curTime));
if (sinceLast < sConfig.Get<uint32>("RetargetInterval"))
if (timeSinceRetarget < sConfig.Get<uint32>("RetargetInterval") && sharesSinceRetarget < sConfig.Get<uint32>("RetargetSharesThreshold"))
return true;
_lastRetarget = curTime;
_lastRetargetTime = curTime;
_lastRetargetShares = _totalShares;
// Check if miner is ok
if (_totalShares > 200 && (double(_totalBadShares)/double(_totalShares)) > 0.9) {
@ -61,7 +63,13 @@ namespace Stratum @@ -61,7 +63,13 @@ namespace Stratum
if (variance < sConfig.Get<uint32>("RetargetVariance"))
return true;
_client->SetDifficulty(newDiff, true);
// If variance is huge, reset difficulty with job discard (DoS prevention)
if (variance > 2000) {
_client->SetDifficulty(newDiff, false);
_client->SendJob(true);
return false;
} else
_client->SetDifficulty(newDiff, true);
return true;
}

9
src/server/poolserver/Stratum/ShareLimiter.h

@ -25,9 +25,9 @@ namespace Stratum @@ -25,9 +25,9 @@ namespace Stratum
public:
ShareLimiter(Client* client) : _client(client), _totalShares(0), _totalBadShares(0)
{
// Minus one to prevent crash when interval is zero
_startTime = Util::Date()-1;
_lastRetarget = _startTime;
// Minus to prevent crash when interval is zero
_startTime = Util::Date()-10;
_lastRetargetTime = _startTime;
}
bool Submit(uint64 diff);
@ -40,7 +40,8 @@ namespace Stratum @@ -40,7 +40,8 @@ namespace Stratum
private:
std::deque<ShareLimiterRecord> _shares;
Client* _client;
uint64 _lastRetarget;
uint64 _lastRetargetTime;
uint64 _lastRetargetShares;
uint64 _startTime;
uint64 _totalShares;

Loading…
Cancel
Save