1
0
mirror of https://github.com/GOSTSec/poolserver synced 2025-01-15 01:00:10 +00:00

More work

This commit is contained in:
Intel 2014-05-04 16:35:37 -04:00
parent 6432acff9d
commit 0fccd298c6
14 changed files with 145 additions and 74 deletions

View File

@ -3,8 +3,9 @@
#include "Util.h" #include "Util.h"
#include "Log.h" #include "Log.h"
template<> DataMgr* DataMgr::singleton = 0;
void DataMgr<Share>::Upload()
void DataMgr::Upload()
{ {
sLog.Info(LOG_SERVER, "We have %u shares", Size()); sLog.Info(LOG_SERVER, "We have %u shares", Size());
@ -15,8 +16,6 @@ void DataMgr<Share>::Upload()
std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `time`, `difficulty`) VALUES "); std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `time`, `difficulty`) VALUES ");
for (int i = 0; i < BULK_COUNT; ++i) for (int i = 0; i < BULK_COUNT; ++i)
{ {
sLog.Info(LOG_SERVER, "Query: %s", query.c_str());
Share share = Pop(); Share share = Pop();
query += Util::FS("(INET_NTOA(%u), '%s', %u, 0, '%s', FROM_UNIXTIME(%u), %u)", share.host, share.username.c_str(), share.result, share.reason.c_str(), share.time, share.diff); query += Util::FS("(INET_NTOA(%u), '%s', %u, 0, '%s', FROM_UNIXTIME(%u), %u)", share.host, share.username.c_str(), share.result, share.reason.c_str(), share.time, share.diff);
@ -28,9 +27,8 @@ void DataMgr<Share>::Upload()
query += ','; query += ',';
} }
sLog.Debug(LOG_SERVER, "Query: %s", query.c_str());
sDatabase.ExecuteAsync(query.c_str()); sDatabase.ExecuteAsync(query.c_str());
} }
} }
DataMgr<Share> sDataMgr;

View File

@ -3,6 +3,7 @@
#include <deque> #include <deque>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/asio.hpp>
#include "Util.h" #include "Util.h"
#include "Share.h" #include "Share.h"
@ -10,19 +11,38 @@
#define BULK_MIN 1 #define BULK_MIN 1
#define BULK_COUNT 50 #define BULK_COUNT 50
template<class T> using namespace boost;
class DataMgr class DataMgr
{ {
// Singleton
private:
static DataMgr* singleton;
public: public:
DataMgr() {}
void Push(T data) static DataMgr* Instance()
{
return singleton;
}
static void Initialize(asio::io_service& io_service)
{
singleton = new DataMgr(io_service);
}
public:
DataMgr(asio::io_service& io_service) : _io_service(io_service), _uploadTimer(io_service)
{
UploadTimerStart();
}
void Push(Share data)
{ {
boost::unique_lock<boost::mutex> lock(_datamutex); boost::unique_lock<boost::mutex> lock(_datamutex);
_datastore.push_back(data); _datastore.push_back(data);
} }
T Pop() Share Pop()
{ {
boost::unique_lock<boost::mutex> lock(_datamutex); boost::unique_lock<boost::mutex> lock(_datamutex);
Share share = _datastore.front(); Share share = _datastore.front();
@ -36,12 +56,28 @@ public:
return _datastore.size(); return _datastore.size();
} }
void UploadTimerStart()
{
_uploadTimer.expires_from_now(boost::posix_time::seconds(3));
_uploadTimer.async_wait(boost::bind(&DataMgr::UploadTimerExpired, this, boost::asio::placeholders::error));
}
void UploadTimerExpired(const boost::system::error_code& /*e*/)
{
Upload();
UploadTimerStart();
}
void Upload(); void Upload();
private: private:
// io service
asio::io_service& _io_service;
// timer
boost::asio::deadline_timer _uploadTimer;
boost::mutex _datamutex; boost::mutex _datamutex;
std::deque<T> _datastore; std::deque<Share> _datastore;
}; };
extern DataMgr<Share> sDataMgr;
#endif #endif

View File

@ -147,7 +147,7 @@ void NetworkMgr::BlockCheck()
void NetworkMgr::BlockCheckTimerStart() void NetworkMgr::BlockCheckTimerStart()
{ {
_blockCheckTimer.expires_from_now(boost::posix_time::seconds(3)); _blockCheckTimer.expires_from_now(boost::posix_time::seconds(2));
_blockCheckTimer.async_wait(boost::bind(&NetworkMgr::BlockCheckTimerExpired, this, boost::asio::placeholders::error)); _blockCheckTimer.async_wait(boost::bind(&NetworkMgr::BlockCheckTimerExpired, this, boost::asio::placeholders::error));
} }
@ -161,12 +161,14 @@ void NetworkMgr::BlockCheckTimerExpired(const boost::system::error_code& /*e*/)
void NetworkMgr::BlockNotifyBind(FBlockNotify f) void NetworkMgr::BlockNotifyBind(FBlockNotify f)
{ {
_blockNotifyBinds.push_back(f); _blockNotifyBinds.push_back(f);
// Send block template
f(_curBlockTmpl, true);
} }
// Block notify timer // Block notify timer
void NetworkMgr::BlockNotifyTimerStart() void NetworkMgr::BlockNotifyTimerStart()
{ {
_blockNotifyTimer.expires_from_now(boost::posix_time::seconds(3)); _blockNotifyTimer.expires_from_now(boost::posix_time::seconds(30));
_blockNotifyTimer.async_wait(boost::bind(&NetworkMgr::BlockNotifyTimerExpired, this, boost::asio::placeholders::error)); _blockNotifyTimer.async_wait(boost::bind(&NetworkMgr::BlockNotifyTimerExpired, this, boost::asio::placeholders::error));
} }

View File

@ -15,7 +15,7 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
Server::Server(asio::io_service& io) : serverLoops(0), io_service(io), uploadtimer(io) Server::Server(asio::io_service& io) : serverLoops(0), io_service(io)
{ {
} }
@ -24,19 +24,6 @@ Server::~Server()
//delete stratumServer; //delete stratumServer;
} }
void AsyncQueryCallback(MySQL::QueryResult result)
{
}
void Server::UploadShares(const boost::system::error_code& /*e*/)
{
sDataMgr.Upload();
uploadtimer.expires_from_now(boost::posix_time::seconds(3)); //repeat rate here
uploadtimer.async_wait(boost::bind(&Server::UploadShares, this, boost::asio::placeholders::error));
}
int Server::Run() int Server::Run()
{ {
sLog.Info(LOG_SERVER, "Server is starting..."); sLog.Info(LOG_SERVER, "Server is starting...");
@ -101,7 +88,7 @@ int Server::Run()
sLog.Info(LOG_SERVER, "Trans: %s", Util::BinToASCII(buf2.vec).c_str());*/ sLog.Info(LOG_SERVER, "Trans: %s", Util::BinToASCII(buf2.vec).c_str());*/
DataMgr::Initialize(io_service);
NetworkMgr::Initialize(io_service); NetworkMgr::Initialize(io_service);
std::vector<std::string> btcrpc = sConfig.Get<std::vector<std::string> >("BitcoinRPC"); std::vector<std::string> btcrpc = sConfig.Get<std::vector<std::string> >("BitcoinRPC");
@ -126,10 +113,6 @@ int Server::Run()
tcp::endpoint endpoint(tcp::v4(), sConfig.Get<uint16>("StratumPort")); tcp::endpoint endpoint(tcp::v4(), sConfig.Get<uint16>("StratumPort"));
srv.Start(endpoint); srv.Start(endpoint);
// Start timer
uploadtimer.expires_from_now(boost::posix_time::seconds(3)); //repeat rate here
uploadtimer.async_wait(boost::bind(&Server::UploadShares, this, boost::asio::placeholders::error));
io_service.run(); io_service.run();

View File

@ -27,7 +27,6 @@ public:
bool InitDatabase(); bool InitDatabase();
boost::asio::deadline_timer uploadtimer;
asio::io_service& io_service; asio::io_service& io_service;
}; };

View File

@ -4,6 +4,7 @@
#include "DataMgr.h" #include "DataMgr.h"
#include "ShareLimiter.h" #include "ShareLimiter.h"
#include "Exception.h" #include "Exception.h"
#include "ServerDatabaseEnv.h"
#include <iostream> #include <iostream>
namespace Stratum namespace Stratum
@ -70,12 +71,28 @@ namespace Stratum
return; return;
} }
// check username
std::string username = params[0].GetString();
if (!_workers.count(username)) {
sLog.Error(LOG_SERVER, "Worker not authenticated");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(24));
response["error"].Add("Unauthorized worker");
response["error"].Add(JSON());
SendMessage(response);
return;
}
uint32 jobid; uint32 jobid;
ByteBuffer jobbuf(Util::ASCIIToBin(params[1].GetString())); ByteBuffer jobbuf(Util::ASCIIToBin(params[1].GetString()));
jobbuf >> jobid; jobbuf >> jobid;
// Check if such job exists // Check if such job exists
if (!_jobs.count(jobid)) { if (!_jobs.count(jobid)) {
DataMgr::Instance()->Push(Share(_ip, username, false, "Job not found", Util::Date(), 1));
JSON response; JSON response;
response["id"] = msg["id"]; response["id"] = msg["id"];
response["result"]; response["result"];
@ -86,9 +103,6 @@ namespace Stratum
return; return;
} }
// check username
std::string username = params[0].GetString();
BinaryData extranonce2 = Util::ASCIIToBin(params[2].GetString()); BinaryData extranonce2 = Util::ASCIIToBin(params[2].GetString());
if (extranonce2.size() != 4) { if (extranonce2.size() != 4) {
sLog.Error(LOG_SERVER, "Wrong extranonce size"); sLog.Error(LOG_SERVER, "Wrong extranonce size");
@ -135,6 +149,8 @@ namespace Stratum
share << extranonce2 << timebuf << noncebuf; share << extranonce2 << timebuf << noncebuf;
if (!job.SubmitShare(share.Binary())) { if (!job.SubmitShare(share.Binary())) {
sLog.Error(LOG_SERVER, "Duplicate share"); sLog.Error(LOG_SERVER, "Duplicate share");
DataMgr::Instance()->Push(Share(_ip, username, false, "Duplicate share", Util::Date(), job.diff));
JSON response; JSON response;
response["id"] = msg["id"]; response["id"] = msg["id"];
response["result"]; response["result"];
@ -161,18 +177,12 @@ namespace Stratum
// Set coinbase tx // Set coinbase tx
block.tx[0] = coinbasetx; block.tx[0] = coinbasetx;
sLog.Info(LOG_SERVER, "Coinbase hash1: %s", Util::BinToASCII(Crypto::SHA256D(coinbasebuf.Binary())).c_str());
sLog.Info(LOG_SERVER, "Coinbase hash2: %s", Util::BinToASCII(coinbasetx.GetHash()).c_str());
// Rebuilds only left side of merkle tree // Rebuilds only left side of merkle tree
block.RebuildMerkleTree(); block.RebuildMerkleTree();
sLog.Info(LOG_SERVER, "Merklehash: %s", Util::BinToASCII(block.merkleRootHash).c_str());
// Get block hash // Get block hash
BinaryData hash = block.GetHash(); BinaryData hash = block.GetHash();
sLog.Info(LOG_SERVER, "Block hash: %s", Util::BinToASCII(hash).c_str());
// Get block target // Get block target
BigInt target(Util::BinToASCII(Util::Reverse(hash)), 16); BigInt target(Util::BinToASCII(Util::Reverse(hash)), 16);
@ -187,6 +197,8 @@ namespace Stratum
// Check if difficulty meets job diff // Check if difficulty meets job diff
if (target > Bitcoin::DiffToTarget(job.diff)) { if (target > Bitcoin::DiffToTarget(job.diff)) {
sLog.Error(LOG_SERVER, "Share above target"); sLog.Error(LOG_SERVER, "Share above target");
DataMgr::Instance()->Push(Share(_ip, username, false, "Share above target", Util::Date(), job.diff));
JSON response; JSON response;
response["id"] = msg["id"]; response["id"] = msg["id"];
response["result"]; response["result"];
@ -203,7 +215,7 @@ namespace Stratum
_server->SubmitBlock(block); _server->SubmitBlock(block);
} else { } else {
sDataMgr.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"];
@ -247,11 +259,25 @@ namespace Stratum
std::string username = msg["params"][0].GetString(); std::string username = msg["params"][0].GetString();
std::string password = msg["params"][1].GetString(); std::string password = msg["params"][1].GetString();
JSON response; MySQL::QueryResult result = sDatabase.Query(Util::FS("SELECT * FROM `pool_worker` WHERE `username` = '%s' and `password` = '%s'", sDatabase.Escape(username).c_str(), sDatabase.Escape(password).c_str()).c_str());
response["id"] = msg["id"].GetInt();
response["error"]; if (result) {
response["result"] = true; _workers.insert(username);
SendMessage(response);
JSON response;
response["id"] = msg["id"].GetInt();
response["error"];
response["result"] = true;
SendMessage(response);
} else {
JSON response;
response["id"] = msg["id"].GetInt();
response["error"].Add(int64(20));
response["error"].Add("Authentication failed");
response["error"].Add(JSON());
response["result"] = true;
SendMessage(response);
}
} }
Job Client::GetJob() Job Client::GetJob()

View File

@ -13,6 +13,7 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include <set>
#define MAX_PACKET 2048 #define MAX_PACKET 2048
@ -142,7 +143,7 @@ namespace Stratum
Stratum::Server* _server; Stratum::Server* _server;
// Authorization // Authorization
std::vector<std::string> _workers; std::set<std::string> _workers;
// Jobs // Jobs
bool _subscribed; bool _subscribed;

View File

@ -1,6 +1,7 @@
#include "ShareLimiter.h" #include "ShareLimiter.h"
#include "Server.h" #include "Server.h"
#include "Client.h" #include "Client.h"
#include "Log.h"
namespace Stratum namespace Stratum
{ {
@ -15,23 +16,33 @@ namespace Stratum
if (sinceLast < RETARGET_INTERVAL) if (sinceLast < RETARGET_INTERVAL)
return true; return true;
_lastRetarget = curTime;
while (_shares.size() && (_shares.front() < curTime - RETARGET_TIME_BUFFER)) while (_shares.size() && (_shares.front() < curTime - RETARGET_TIME_BUFFER))
_shares.pop_front(); _shares.pop_front();
uint32 interval = std::min(curTime - _startTime, uint64(RETARGET_TIME_BUFFER)); uint32 interval = std::min(curTime - _startTime, uint64(RETARGET_TIME_BUFFER));
// Calculate shares/min // Calculate shares/min
double speed = (_shares.size()*60) / interval; double speed = double(_shares.size()*60) / double(interval);
// Calculate difference from pool target in % // Calculate difference from pool target in %
double variance = (speed - RETARGET_SHARES_PER_MIN) / RETARGET_SHARES_PER_MIN; double variance = speed / double(RETARGET_SHARES_PER_MIN);
sLog.Info(LOG_SERVER, "Miner variance: %f speed: %f", variance, speed);
// Check if we need to retarget // Check if we need to retarget
if (std::abs(variance)*100 < RETARGET_VARIANCE) if (variance*100 < RETARGET_VARIANCE)
return true; return true;
uint64 newDiff = double(_client->GetDifficulty()) * variance; uint64 newDiff = double(_client->GetDifficulty()) * variance;
if (newDiff < 1)
newDiff = 1;
if (newDiff > RETARGET_MAXDIFF)
newDiff = RETARGET_MAXDIFF;
_client->SetDifficulty(newDiff, true); _client->SetDifficulty(newDiff, true);
return true; return true;

View File

@ -6,29 +6,23 @@
#include <deque> #include <deque>
#define RETARGET_INTERVAL 60 #define RETARGET_INTERVAL 20
#define RETARGET_TIME_BUFFER 60*5 #define RETARGET_TIME_BUFFER 60*5
#define RETARGET_SHARES_PER_MIN 15 #define RETARGET_SHARES_PER_MIN 15
#define RETARGET_VARIANCE 40 #define RETARGET_VARIANCE 40
#define RETARGET_MAXDIFF 1000000
namespace Stratum namespace Stratum
{ {
class Client; class Client;
class ShareLimiterRecord
{
public:
ShareLimiterRecord(uint64 atime, uint64 adiff) : time(atime), diff(adiff) {}
uint64 time;
uint64 diff;
};
class ShareLimiter class ShareLimiter
{ {
public: public:
ShareLimiter(Client* client) : _client(client), _lastRetarget(0) ShareLimiter(Client* client) : _client(client)
{ {
_startTime = Util::Date(); _startTime = Util::Date();
_lastRetarget = _startTime;
} }
bool Submit(); bool Submit();

View File

@ -82,6 +82,15 @@ namespace MySQL
return _stmts[index]; return _stmts[index];
} }
std::string Escape(std::string text)
{
char* buf = new char[text.length()*2 + 1];
mysql_real_escape_string(_mysql, buf, text.c_str(), text.length());
std::string result(buf);
delete buf;
return result;
}
private: private:
bool _Query(const char *sql, MYSQL_RES** result, MYSQL_FIELD** fields, uint64& rowCount, uint32& fieldCount); bool _Query(const char *sql, MYSQL_RES** result, MYSQL_FIELD** fields, uint64& rowCount, uint32& fieldCount);
bool _Query(PreparedStatement* stmt, MYSQL_RES** result, MYSQL_STMT** resultSTMT, uint32& fieldCount); bool _Query(PreparedStatement* stmt, MYSQL_RES** result, MYSQL_STMT** resultSTMT, uint32& fieldCount);

View File

@ -40,13 +40,22 @@ namespace MySQL
class DatabaseQueryOperation : public DatabaseOperation class DatabaseQueryOperation : public DatabaseOperation
{ {
public: public:
DatabaseQueryOperation(const char* query, DatabaseCallback callback = NULL): DatabaseOperation(), _query(query), _callback(callback) {}; DatabaseQueryOperation(const char* query, DatabaseCallback callback = NULL): DatabaseOperation(), _callback(callback)
{
_query = new char[strlen(query)];
strcpy(_query, const_cast<char *>(query));
}
~DatabaseQueryOperation()
{
delete[] _query;
}
void Execute(); void Execute();
private: private:
DatabaseCallback _callback; DatabaseCallback _callback;
const char* _query; char* _query;
}; };
typedef Util::SynchronisedQueue<DatabaseOperation*> DatabaseWorkQueue; typedef Util::SynchronisedQueue<DatabaseOperation*> DatabaseWorkQueue;

View File

@ -93,6 +93,14 @@ namespace MySQL
return new PreparedStatement(stmtid); return new PreparedStatement(stmtid);
} }
std::string Escape(std::string text)
{
DatabaseConnection* conn = GetSyncConnection();
std::string result = conn->Escape(text);
conn->Unlock();
return result;
}
private: private:
DatabaseConnection* GetSyncConnection() DatabaseConnection* GetSyncConnection()
{ {

View File

@ -18,14 +18,9 @@ std::string Util::Date(const char* format, bool utc)
return ss.str(); return ss.str();
} }
uint32 Util::Date(bool utc) uint32 Util::Date()
{ {
boost::posix_time::ptime now; boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time();
if (utc)
now = boost::posix_time::second_clock::universal_time();
else
now = boost::posix_time::second_clock::local_time();
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));
boost::posix_time::time_duration diff = now - epoch; boost::posix_time::time_duration diff = now - epoch;
return diff.total_seconds(); return diff.total_seconds();

View File

@ -19,7 +19,7 @@
namespace Util namespace Util
{ {
std::string Date(const char* format, bool utc = false); std::string Date(const char* format, bool utc = false);
uint32 Date(bool utc = true); uint32 Date();
std::string FS(const char *str, ...); std::string FS(const char *str, ...);
std::vector<std::string> Explode(std::string input, std::string delim); std::vector<std::string> Explode(std::string input, std::string delim);