mirror of
https://github.com/GOSTSec/poolserver
synced 2025-01-14 08:47:53 +00:00
Improved ShareLimiter
This commit is contained in:
parent
456fd37476
commit
bd229a0dac
@ -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")
|
||||
;
|
||||
|
@ -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
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
// 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
|
||||
// Jobs
|
||||
bool _subscribed;
|
||||
uint32 _extranonce;
|
||||
std::map<uint64, Job> _jobs;
|
||||
std::map<uint64, Job*> _jobs;
|
||||
uint32 _jobid;
|
||||
|
||||
// Share limiting
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Util.h"
|
||||
#include "BigNum.h"
|
||||
#include <set>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
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
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex _mtx;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
private:
|
||||
std::deque<ShareLimiterRecord> _shares;
|
||||
Client* _client;
|
||||
uint64 _lastRetarget;
|
||||
uint64 _lastRetargetTime;
|
||||
uint64 _lastRetargetShares;
|
||||
uint64 _startTime;
|
||||
|
||||
uint64 _totalShares;
|
||||
|
Loading…
Reference in New Issue
Block a user