mirror of https://github.com/GOSTSec/poolserver
Intel
11 years ago
31 changed files with 833 additions and 236 deletions
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
#include "DataMgr.h" |
||||
#include "ServerDatabaseEnv.h" |
||||
#include "Util.h" |
||||
#include "Log.h" |
||||
|
||||
template<> |
||||
void DataMgr<Share>::Upload() |
||||
{ |
||||
sLog.Info(LOG_SERVER, "We have %u shares", Size()); |
||||
|
||||
while (Size() > BULK_MIN) |
||||
{ |
||||
sLog.Info(LOG_SERVER, "Uploading %u shares to database", Size()); |
||||
|
||||
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) |
||||
{ |
||||
sLog.Info(LOG_SERVER, "Query: %s", query.c_str()); |
||||
|
||||
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); |
||||
|
||||
if (!Size()) |
||||
break; |
||||
|
||||
if (i != BULK_COUNT-1) |
||||
query += ','; |
||||
} |
||||
|
||||
|
||||
sDatabase.ExecuteAsync(query.c_str()); |
||||
} |
||||
} |
||||
|
||||
DataMgr<Share> sDataMgr; |
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
#ifndef DATAMGR_H_ |
||||
#define DATAMGR_H_ |
||||
|
||||
#include <deque> |
||||
#include <boost/thread.hpp> |
||||
|
||||
#include "Util.h" |
||||
#include "Share.h" |
||||
|
||||
#define BULK_MIN 1 |
||||
#define BULK_COUNT 50 |
||||
|
||||
template<class T> |
||||
class DataMgr |
||||
{ |
||||
public: |
||||
DataMgr() {} |
||||
|
||||
void Push(T data) |
||||
{ |
||||
boost::unique_lock<boost::mutex> lock(_datamutex); |
||||
_datastore.push_back(data); |
||||
} |
||||
|
||||
T Pop() |
||||
{ |
||||
boost::unique_lock<boost::mutex> lock(_datamutex); |
||||
Share share = _datastore.front(); |
||||
_datastore.pop_front(); |
||||
return share; |
||||
} |
||||
|
||||
size_t Size() |
||||
{ |
||||
boost::unique_lock<boost::mutex> lock(_datamutex); |
||||
return _datastore.size(); |
||||
} |
||||
|
||||
void Upload(); |
||||
private: |
||||
boost::mutex _datamutex; |
||||
std::deque<T> _datastore; |
||||
}; |
||||
|
||||
extern DataMgr<Share> sDataMgr; |
||||
|
||||
#endif |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
#ifndef SHARE_H_ |
||||
#define SHARE_H_ |
||||
|
||||
#include <string> |
||||
|
||||
#include "Common.h" |
||||
|
||||
class Share |
||||
{ |
||||
public: |
||||
Share(uint32 ahost, std::string ausername, bool aresult, std::string areason, uint64 atime, uint64 adiff): |
||||
host(ahost), username(ausername), result(aresult), reason(areason), time(atime), diff(adiff) {} |
||||
|
||||
uint64 host; |
||||
std::string username; |
||||
bool result; |
||||
std::string reason; |
||||
uint64 time; |
||||
uint64 diff; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,188 @@
@@ -0,0 +1,188 @@
|
||||
#include "NetworkMgr.h" |
||||
#include "Config.h" |
||||
|
||||
NetworkMgr* NetworkMgr::singleton = 0; |
||||
|
||||
NetworkMgr::NetworkMgr(asio::io_service& io_service) : _io_service(io_service), _blockNotifyTimer(io_service), _blockCheckTimer(io_service), _blockHeight(0) |
||||
{ |
||||
BlockCheckTimerStart(); |
||||
BlockNotifyTimerStart(); |
||||
} |
||||
|
||||
NetworkMgr::~NetworkMgr() |
||||
{ |
||||
for (int i = 0; i < _cons.size(); ++i) |
||||
delete _cons[i]; |
||||
} |
||||
|
||||
// Bitcoin daemon connection
|
||||
void NetworkMgr::Connect(JSONRPCConnectionInfo coninfo) |
||||
{ |
||||
JSONRPC* bitcoinrpc = new JSONRPC(); |
||||
bitcoinrpc->Connect(coninfo); |
||||
|
||||
JSON response = bitcoinrpc->Query("getinfo"); |
||||
|
||||
if (response["error"].GetType() != JSON_NULL) |
||||
throw Exception(Util::FS("Failed to get response from bitcoin rpc: %s", response["error"].GetString().c_str())); |
||||
|
||||
sLog.Info(LOG_SERVER, "Connected to Bitcoin RPC at %s:%s", coninfo.Host.c_str(), coninfo.Port.c_str()); |
||||
|
||||
_cons.push_back(bitcoinrpc); |
||||
|
||||
// Fetch block height on first connection
|
||||
if (_cons.size() == 1) |
||||
BlockCheck(); |
||||
} |
||||
|
||||
// Get new block template
|
||||
void NetworkMgr::UpdateBlockTemplate() |
||||
{ |
||||
// Might be called by block notify timer and block check timer so we need a lock
|
||||
boost::lock_guard<boost::mutex> guard(_mtxBlockTmpl); |
||||
|
||||
for (int i = 0; i < _cons.size(); ++i) |
||||
{ |
||||
try { |
||||
JSON response = _cons[i]->Query("getblocktemplate"); |
||||
|
||||
// New blocks may not appear on all daemons the same time
|
||||
if (response["height"].GetInt() < _blockHeight) |
||||
continue; |
||||
|
||||
Bitcoin::BlockPtr block = Bitcoin::BlockPtr(new Bitcoin::Block()); |
||||
|
||||
block->version = response["version"].GetInt(); |
||||
block->prevBlockHash = Util::Reverse(Util::ASCIIToBin(response["previousblockhash"].GetString())); |
||||
block->time = response["curtime"].GetInt(); |
||||
// Set bits
|
||||
ByteBuffer bitbuf(Util::Reverse(Util::ASCIIToBin(response["bits"].GetString()))); |
||||
bitbuf >> block->bits; |
||||
|
||||
// Add coinbase tx
|
||||
BinaryData pubkey = Util::ASCIIToBin(sConfig.Get<std::string>("MiningAddress")); |
||||
block->tx.push_back(Bitcoin::CreateCoinbaseTX(_blockHeight, pubkey, response["coinbasevalue"].GetInt())); |
||||
|
||||
// Add other transactions
|
||||
JSON trans = response["transactions"]; |
||||
for (uint64 tidx = 0; tidx < trans.Size(); ++tidx) { |
||||
ByteBuffer txbuf(Util::ASCIIToBin(trans[tidx]["data"].GetString())); |
||||
Bitcoin::Transaction tx; |
||||
txbuf >> tx; |
||||
block->tx.push_back(tx); |
||||
} |
||||
|
||||
// Genrate merkle tree
|
||||
block->BuildMerkleTree(); |
||||
|
||||
// Set
|
||||
_curBlockTmpl = block; |
||||
|
||||
sLog.Debug(LOG_SERVER, "Fetched block template from rpc #%u", i); |
||||
|
||||
// Break from loop
|
||||
break; |
||||
} catch (std::exception& e) { |
||||
sLog.Error(LOG_SERVER, "Failed to fetch block template from daemon #%u: %s", i, e.what()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Submit new block
|
||||
bool NetworkMgr::SubmitBlock(Bitcoin::Block block) |
||||
{ |
||||
// Serialize block
|
||||
ByteBuffer blockbuf; |
||||
blockbuf << block; |
||||
|
||||
for (int i = 0; i < _cons.size(); ++i) |
||||
{ |
||||
try { |
||||
JSON params; |
||||
params.Add(Util::BinToASCII(blockbuf.Binary())); |
||||
JSON response = _cons[i]->Query("submitblock", params); |
||||
|
||||
if (response["result"].GetType() == JSON_NULL) { |
||||
sLog.Info(LOG_SERVER, "Block accepted! YAY!"); |
||||
BlockCheck(); |
||||
return true; |
||||
} else { |
||||
sLog.Error(LOG_SERVER, "Block rejected: %s", response["error"].GetString().c_str()); |
||||
} |
||||
} catch (std::exception& e) { |
||||
sLog.Error(LOG_SERVER, "Exception caught while submiting block: %s", e.what()); |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// Check for new blocks
|
||||
void NetworkMgr::BlockCheck() |
||||
{ |
||||
// Might be called twice from timer and when block is found
|
||||
boost::lock_guard<boost::mutex> guard(_mtxBlockCheck); |
||||
|
||||
for (int i = 0; i < _cons.size(); ++i) |
||||
{ |
||||
try { |
||||
JSON response = _cons[i]->Query("getinfo"); |
||||
uint32 curBlock = response["blocks"].GetInt(); |
||||
|
||||
if (curBlock > _blockHeight) { |
||||
sLog.Debug(LOG_SERVER, "New block on network! Height: %u", curBlock); |
||||
_blockHeight = curBlock; |
||||
|
||||
// Update block template
|
||||
UpdateBlockTemplate(); |
||||
|
||||
// Send notifications (and reset work)
|
||||
BlockNotifySend(true); |
||||
} |
||||
} catch (std::exception& e) { |
||||
sLog.Error(LOG_SERVER, "Failed to fetch block height from daemon #%u: %s", i, e.what()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void NetworkMgr::BlockCheckTimerStart() |
||||
{ |
||||
_blockCheckTimer.expires_from_now(boost::posix_time::seconds(3)); |
||||
_blockCheckTimer.async_wait(boost::bind(&NetworkMgr::BlockCheckTimerExpired, this, boost::asio::placeholders::error)); |
||||
} |
||||
|
||||
void NetworkMgr::BlockCheckTimerExpired(const boost::system::error_code& /*e*/) |
||||
{ |
||||
BlockCheck(); |
||||
BlockCheckTimerStart(); |
||||
} |
||||
|
||||
// Bind for receiving block notifications
|
||||
void NetworkMgr::BlockNotifyBind(FBlockNotify f) |
||||
{ |
||||
_blockNotifyBinds.push_back(f); |
||||
} |
||||
|
||||
// Block notify timer
|
||||
void NetworkMgr::BlockNotifyTimerStart() |
||||
{ |
||||
_blockNotifyTimer.expires_from_now(boost::posix_time::seconds(3)); |
||||
_blockNotifyTimer.async_wait(boost::bind(&NetworkMgr::BlockNotifyTimerExpired, this, boost::asio::placeholders::error)); |
||||
} |
||||
|
||||
void NetworkMgr::BlockNotifyTimerExpired(const boost::system::error_code& /*e*/) |
||||
{ |
||||
sLog.Debug(LOG_SERVER, "Sending block template update"); |
||||
|
||||
UpdateBlockTemplate(); |
||||
BlockNotifySend(); |
||||
|
||||
BlockNotifyTimerStart(); |
||||
} |
||||
|
||||
// Send block notification to all subscribers
|
||||
void NetworkMgr::BlockNotifySend(bool newBlock) |
||||
{ |
||||
for (int i = 0; i < _blockNotifyBinds.size(); ++i) |
||||
_io_service.post(boost::bind(_blockNotifyBinds[i], _curBlockTmpl, newBlock)); |
||||
} |
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
#ifndef NETWORKMGR_H_ |
||||
#define NETWORKMGR_H_ |
||||
|
||||
// Provides high level interaction with bitcoin daemon
|
||||
|
||||
#include "JSONRPC.h" |
||||
#include "Bitcoin.h" |
||||
#include "Log.h" |
||||
|
||||
#include <vector> |
||||
#include <boost/asio.hpp> |
||||
#include <boost/function.hpp> |
||||
#include <boost/thread/mutex.hpp> |
||||
|
||||
using namespace boost; |
||||
|
||||
typedef boost::function<void (Bitcoin::BlockPtr /*blockTmpl*/, bool /*newBlock*/)> FBlockNotify; |
||||
|
||||
class NetworkMgr |
||||
{ |
||||
// Singleton
|
||||
private: |
||||
static NetworkMgr* singleton; |
||||
public: |
||||
|
||||
static NetworkMgr* Instance() |
||||
{ |
||||
return singleton; |
||||
} |
||||
static void Initialize(asio::io_service& io_service) |
||||
{ |
||||
singleton = new NetworkMgr(io_service); |
||||
} |
||||
|
||||
public: |
||||
NetworkMgr(asio::io_service& io_service); |
||||
~NetworkMgr(); |
||||
|
||||
// Bitcoin daemon connection
|
||||
void Connect(JSONRPCConnectionInfo coninfo); |
||||
|
||||
// Get new block template
|
||||
void UpdateBlockTemplate(); |
||||
|
||||
// Submit new block
|
||||
bool SubmitBlock(Bitcoin::Block block); |
||||
|
||||
// Checking for blocks
|
||||
void BlockCheck(); |
||||
void BlockCheckTimerStart(); |
||||
void BlockCheckTimerExpired(const boost::system::error_code& /*e*/); |
||||
|
||||
// Bind for receiving block notifications
|
||||
void BlockNotifyBind(FBlockNotify f); |
||||
|
||||
// Block notify timer
|
||||
void BlockNotifyTimerStart(); |
||||
void BlockNotifyTimerExpired(const boost::system::error_code& /*e*/); |
||||
|
||||
// Send block notification to all subscribers
|
||||
void BlockNotifySend(bool newBlock = false); |
||||
|
||||
private: |
||||
// Holds subscriptions for block notifications
|
||||
std::vector<FBlockNotify> _blockNotifyBinds; |
||||
boost::asio::deadline_timer _blockNotifyTimer; |
||||
|
||||
// Checking for new blocks
|
||||
boost::asio::deadline_timer _blockCheckTimer; |
||||
boost::mutex _mtxBlockCheck; |
||||
uint32 _blockHeight; |
||||
|
||||
// Connections to bitcoin rpc
|
||||
std::vector<JSONRPC*> _cons; |
||||
|
||||
// Current block template
|
||||
Bitcoin::BlockPtr _curBlockTmpl; |
||||
boost::mutex _mtxBlockTmpl; |
||||
|
||||
// ASIO
|
||||
asio::io_service& _io_service; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
#include "ShareLimiter.h" |
||||
#include "Server.h" |
||||
#include "Client.h" |
||||
|
||||
namespace Stratum |
||||
{ |
||||
// Returning false will stop any further share verifications (DoS prevention, etc)
|
||||
bool ShareLimiter::Submit() |
||||
{ |
||||
uint64 curTime = Util::Date(); |
||||
uint64 sinceLast = curTime - _lastRetarget; |
||||
|
||||
_shares.push_back(curTime); |
||||
|
||||
if (sinceLast < RETARGET_INTERVAL) |
||||
return true; |
||||
|
||||
while (_shares.size() && (_shares.front() < curTime - RETARGET_TIME_BUFFER)) |
||||
_shares.pop_front(); |
||||
|
||||
uint32 interval = std::min(curTime - _startTime, uint64(RETARGET_TIME_BUFFER)); |
||||
|
||||
// Calculate shares/min
|
||||
double speed = (_shares.size()*60) / interval; |
||||
|
||||
// Calculate difference from pool target in %
|
||||
double variance = (speed - RETARGET_SHARES_PER_MIN) / RETARGET_SHARES_PER_MIN; |
||||
|
||||
// Check if we need to retarget
|
||||
if (std::abs(variance)*100 < RETARGET_VARIANCE) |
||||
return true; |
||||
|
||||
uint64 newDiff = double(_client->GetDifficulty()) * variance; |
||||
|
||||
_client->SetDifficulty(newDiff, true); |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
#ifndef SHARELIMITER_H_ |
||||
#define SHARELIMITER_H_ |
||||
|
||||
#include "Common.h" |
||||
#include "Util.h" |
||||
|
||||
#include <deque> |
||||
|
||||
#define RETARGET_INTERVAL 60 |
||||
#define RETARGET_TIME_BUFFER 60*5 |
||||
#define RETARGET_SHARES_PER_MIN 15 |
||||
#define RETARGET_VARIANCE 40 |
||||
|
||||
namespace Stratum |
||||
{ |
||||
class Client; |
||||
|
||||
class ShareLimiterRecord |
||||
{ |
||||
public: |
||||
ShareLimiterRecord(uint64 atime, uint64 adiff) : time(atime), diff(adiff) {} |
||||
uint64 time; |
||||
uint64 diff; |
||||
}; |
||||
|
||||
class ShareLimiter |
||||
{ |
||||
public: |
||||
ShareLimiter(Client* client) : _client(client), _lastRetarget(0) |
||||
{ |
||||
_startTime = Util::Date(); |
||||
} |
||||
|
||||
bool Submit(); |
||||
|
||||
private: |
||||
std::deque<uint64> _shares; |
||||
Client* _client; |
||||
uint64 _lastRetarget; |
||||
uint64 _startTime; |
||||
}; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
#ifndef EXCEPTION_H_ |
||||
#define EXCEPTION_H_ |
||||
|
||||
class Exception: public std::exception |
||||
{ |
||||
public: |
||||
Exception(const char *text) |
||||
{ |
||||
_msg.assign(text); |
||||
} |
||||
|
||||
Exception(std::string text) |
||||
{ |
||||
_msg.assign(text); |
||||
} |
||||
|
||||
virtual ~Exception() throw () {} |
||||
|
||||
virtual const char* what() const throw () { |
||||
return _msg.c_str(); |
||||
} |
||||
|
||||
protected: |
||||
std::string _msg; |
||||
}; |
||||
|
||||
#endif |
Loading…
Reference in new issue