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[])
("StratumPort,sp", boost::program_options::value<uint16_t>()->default_value(3333), "Stratum server port") ("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") ("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") ("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)") ("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") ("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)") ("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") ("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
void Client::SendJob(bool clean) void Client::SendJob(bool clean)
{ {
if (clean) if (clean)
_jobs.clear(); CleanJobs();
Job job = GetJob(); Job* job = GetJob();
uint32 jobid = _jobid++; uint32 jobid = _jobid++;
_jobs[jobid] = job; _jobs[jobid] = job;
@ -51,14 +51,14 @@ namespace Stratum
JSON merkle_branch(JSON_ARRAY); JSON merkle_branch(JSON_ARRAY);
uint32 j = 0; 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; j += size;
} }
// Reverse prev block hash every 4 bytes... Makes a lot of sense... // 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); std::vector<uint32> prevhash(8);
prevhashbuf >> prevhash[7] >> prevhash[6] >> prevhash[5] >> prevhash[4] >> prevhash[3] >> prevhash[2] >> prevhash[1] >> prevhash[0]; prevhashbuf >> prevhash[7] >> prevhash[6] >> prevhash[5] >> prevhash[4] >> prevhash[3] >> prevhash[2] >> prevhash[1] >> prevhash[0];
ByteBuffer prevhashfixed; ByteBuffer prevhashfixed;
@ -67,12 +67,12 @@ namespace Stratum
JSON params; JSON params;
params.Add(jobss.str()); params.Add(jobss.str());
params.Add(Util::BinToASCII(prevhashfixed.Binary())); params.Add(Util::BinToASCII(prevhashfixed.Binary()));
params.Add(Util::BinToASCII(job.coinbase1)); params.Add(Util::BinToASCII(job->coinbase1));
params.Add(Util::BinToASCII(job.coinbase2)); params.Add(Util::BinToASCII(job->coinbase2));
params.Add(merkle_branch); params.Add(merkle_branch);
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job.block->version).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->bits).Binary())));
params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job.block->time).Binary()))); params.Add(Util::BinToASCII(Util::Reverse(ByteBuffer(job->block->time).Binary())));
params.Add(clean); params.Add(clean);
JSON msg; JSON msg;
@ -122,10 +122,10 @@ namespace Stratum
} }
// Get job // Get job
Job& job = _jobs[jobid]; Job* job = _jobs[jobid];
// Share limiter // Share limiter
if (!_shareLimiter.Submit(job.diff)) { if (!_shareLimiter.Submit(job->diff)) {
JSON response; JSON response;
response["id"] = msg["id"]; response["id"] = msg["id"];
response["result"]; response["result"];
@ -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); 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()); 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(); _shareLimiter.LogBad();
JSON response; JSON response;
@ -199,7 +199,7 @@ namespace Stratum
} }
// Copy block we are working on // Copy block we are working on
Bitcoin::Block block = *job.block; Bitcoin::Block block = *job->block;
// Start assembling the block // Start assembling the block
timebuf >> block.time; timebuf >> block.time;
@ -208,7 +208,7 @@ namespace Stratum
// Assemble coinbase // Assemble coinbase
Bitcoin::Transaction coinbasetx; Bitcoin::Transaction coinbasetx;
ByteBuffer coinbasebuf; ByteBuffer coinbasebuf;
coinbasebuf << job.coinbase1 << _extranonce << extranonce2 << job.coinbase2; coinbasebuf << job->coinbase1 << _extranonce << extranonce2 << job->coinbase2;
coinbasebuf >> coinbasetx; coinbasebuf >> coinbasetx;
// Set coinbase tx // Set coinbase tx
@ -224,9 +224,9 @@ namespace Stratum
BigInt target(Util::BinToASCII(Util::Reverse(hash)), 16); BigInt target(Util::BinToASCII(Util::Reverse(hash)), 16);
// Check if difficulty meets job diff // 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()); 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(); _shareLimiter.LogBad();
JSON response; JSON response;
@ -240,11 +240,11 @@ namespace Stratum
} }
// Check if block meets criteria // Check if block meets criteria
if (target <= job.blockTarget) { if (target <= job->blockTarget) {
sLog.Info(LOG_STRATUM, "We have found a block candidate!"); 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 // 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)) { if (_server->SubmitBlock(block)) {
std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, `time`, `difficulty`) VALUES "); std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `solution`, `time`, `difficulty`) VALUES ");
@ -259,7 +259,7 @@ namespace Stratum
return; return;
} }
} else { } 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; JSON response;
response["id"] = msg["id"]; response["id"] = msg["id"];
@ -330,17 +330,17 @@ namespace Stratum
} }
} }
Job Client::GetJob() Job* Client::GetJob()
{ {
Job job; Job* job = new Job();
job.block = _server->GetWork(); job->block = _server->GetWork();
job.diff = _diff; job->diff = _diff;
job.jobTarget = Bitcoin::DiffToTarget(job.diff); job->jobTarget = Bitcoin::DiffToTarget(job->diff);
job.blockTarget = Bitcoin::TargetFromBits(job.block->bits); job->blockTarget = Bitcoin::TargetFromBits(job->block->bits);
// Serialize transaction // Serialize transaction
ByteBuffer coinbasebuf; ByteBuffer coinbasebuf;
coinbasebuf << job.block->tx[0]; coinbasebuf << job->block->tx[0];
BinaryData coinbase = coinbasebuf.Binary(); BinaryData coinbase = coinbasebuf.Binary();
// Split coinbase // Split coinbase
@ -350,8 +350,8 @@ namespace Stratum
// tx.script (varint) - 2 bytes // tx.script (varint) - 2 bytes
// tx.script (block height) - 4 bytes // tx.script (block height) - 4 bytes
uint32 cbsplit = 4 + 32 + 4 + 2 + 4; uint32 cbsplit = 4 + 32 + 4 + 2 + 4;
job.coinbase1 = BinaryData(coinbase.begin(), coinbase.begin() + cbsplit); job->coinbase1 = BinaryData(coinbase.begin(), coinbase.begin() + cbsplit);
job.coinbase2 = BinaryData(coinbase.begin() + cbsplit + 8, coinbase.end()); // plus extranonce size job->coinbase2 = BinaryData(coinbase.begin() + cbsplit + 8, coinbase.end()); // plus extranonce size
return job; return job;
} }

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

@ -27,12 +27,13 @@ namespace Stratum
public: 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) 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"); _minDiff = sConfig.Get<uint32>("RetargetMinDiff");
} }
~Client() ~Client()
{ {
CleanJobs();
sLog.Info(LOG_STRATUM, "%u: I'm going out! Cya!", _ip); sLog.Info(LOG_STRATUM, "%u: I'm going out! Cya!", _ip);
} }
@ -89,7 +90,14 @@ namespace Stratum
} }
// Gets new job from the server // 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 // Worker difficulty
uint64 GetDifficulty() uint64 GetDifficulty()
@ -177,7 +185,7 @@ namespace Stratum
// Jobs // Jobs
bool _subscribed; bool _subscribed;
uint32 _extranonce; uint32 _extranonce;
std::map<uint64, Job> _jobs; std::map<uint64, Job*> _jobs;
uint32 _jobid; uint32 _jobid;
// Share limiting // Share limiting

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

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

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

@ -12,14 +12,16 @@ namespace Stratum
++_totalShares; ++_totalShares;
uint64 curTime = Util::Date(); uint64 curTime = Util::Date();
uint64 sinceLast = curTime - _lastRetarget; uint64 timeSinceRetarget = curTime - _lastRetargetTime;
uint64 sharesSinceRetarget = _totalShares - _lastRetargetShares;
_shares.push_back(ShareLimiterRecord(diff, curTime)); _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; return true;
_lastRetarget = curTime; _lastRetargetTime = curTime;
_lastRetargetShares = _totalShares;
// Check if miner is ok // Check if miner is ok
if (_totalShares > 200 && (double(_totalBadShares)/double(_totalShares)) > 0.9) { if (_totalShares > 200 && (double(_totalBadShares)/double(_totalShares)) > 0.9) {
@ -61,7 +63,13 @@ namespace Stratum
if (variance < sConfig.Get<uint32>("RetargetVariance")) if (variance < sConfig.Get<uint32>("RetargetVariance"))
return true; 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; return true;
} }

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

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

Loading…
Cancel
Save