Skip to content

Commit

Permalink
- Pool reconnection issues fixed
Browse files Browse the repository at this point in the history
- Rejected shares strategies added
  • Loading branch information
BScrk committed Oct 30, 2017
1 parent 1e663b1 commit 6b93a81
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 73 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,30 @@ The proxy will automatically listen on port 8000 for miners.

# Configuration
* all configs in file config.json to change settings.

```
{
"wallet": "<Your wallet>",
"password" : "<Pool password or just 'x'>",
"port": <Proxy port>,
"proxy_name" : "<Proxy default name>" (shown on the pool if enable_worker_id set to false),
"enable_worker_id": true|false (send worker name to the pool or not),
"pool" : { "host" : "<HOST>" , "port" : <PORT>, "ssl" : true|false },
"pool_failover_enabled": true|false,
"pool_failover" : [ { "host" : "<HOST>" , "port" : <PORT>, "ssl" : true|false },
{ "host" : "<HOST>" , "port" : <PORT>, "ssl" : true|false },
{ "host" : "<HOST>" , "port" : <PORT>, "ssl" : true|false }],
"restart_delay": <delay before restarting the proxy on error>,
"on_rejected_share": {
"strategy" : "<On Rejected Share strategy>" (continue / kill / restart),
"threshold" : <number of rejected shares before applying strategy>
},
"debug" : true|false
}
```
### On Rejected Share strategies :
* `continue` : ignore and continue
* `restart` : Restart the proxy (without pm2)
* `kill` : Kill the process (hard restart using pm2)

# Miners command line

Expand Down
7 changes: 6 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@
{ "host" : "us1-zcash.flypool.org" , "port" : 3333 , "ssl" : false },
{ "host" : "cn1-zcash.flypool.org" , "port" : 3333 , "ssl" : false },
{ "host" : "asia1-zcash.flypool.org", "port" : 3333 , "ssl" : false }],
"debug" : false
"restart_delay": 10,
"on_rejected_share": {
"strategy" : "restart",
"threshold" : 5
},
"debug" : false
}
92 changes: 66 additions & 26 deletions lib/miners_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var MinersController = function(poolproxy) {
this.miners = new Map();
this.proxy = poolproxy;
this.id = 10;
this.totalRejectedShares = 0;
logger.dbg('[INFO] Workers controller created');
this.listener = net.createServer( (newConnection) => {
var miner = new Miner(newConnection,this); // create new miner
Expand Down Expand Up @@ -47,16 +48,30 @@ MinersController.prototype.removeMiner = function (peer_id) {
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MinersController.prototype.destroy = function (obj) {
logger.dbg('[MINERS] Destroy controller');
this.listener.close();
delete this.listener;
this.listener = null;
this.reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MinersController.prototype.reset = function (obj) {
logger.dbg('[MINERS] Close workers connections');
this.miners.forEach( (miner,peer_id) => {
logger.dbg(' >> Close miner connection ' + miner.name);
miner.connection.end();
delete miner.connection;
miner.connection = null;
this.miners.delete(peer_id);
});
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MinersController.prototype.outputRegSharesStats = function () {
logger.err('Too many rejected shares : ' + this.totalRejectedShares);
this.miners.forEach(function(value,key) {
logger.warn(' - ' + value.name + ' : ' + value.rejectedShares + ' shares rejected');
});
}

// ----------------------------------------------------------------------------
var Miner = function(connection,controller){
Expand All @@ -67,6 +82,7 @@ var Miner = function(connection,controller){
this.connection = connection;
this.status = "none";
this.reqid = 0;
this.rejectedShares = 0;
this.connection.on('error', (err)=>{this.onError(err);});
this.connection.on('data', (data)=>{})
.pipe(ldj.parse({strict: true}))
Expand All @@ -84,33 +100,35 @@ Miner.prototype.onError = function(error) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Miner.prototype.onData = function(obj) {
logger.dbg('[MINER<'+this.id+'>:IN] ' + JSON.stringify(obj));
this.lastReqId = obj.id;
if(obj.method == "mining.subscribe"){
if(this.ctrl.proxy.sessionId == null){
this.Error("No pool session id");
}else{
this.send({id:this.lastReqId,result:[this.ctrl.proxy.sessionId,this.ctrl.proxy.sessionId],error:null});
}
}else if(obj.method == "mining.authorize"){
logger.log ( "New peer connected : " + chalk.blueBright(obj.params[0]));
this.name = obj.params[0];
if(this.ctrl.proxy.status != "ready"){
this.Error("Proxy not authorised yet");
}else{

logger.log ( this.ctrl.miners.size + " peer(s) mining on this proxy");
this.send({id:this.lastReqId,result:true,error:null});
this.send({id:null,method:"mining.set_target", params:this.ctrl.proxy.last_target});
this.send({id:null,method:"mining.notify", params:this.ctrl.proxy.last_notif});
if(this.connection){
this.lastReqId = obj.id;
if(obj.method == "mining.subscribe"){
if(this.ctrl.proxy.sessionId == null){
this.Error("No pool session id");
}else{
this.send({id:this.lastReqId,result:[this.ctrl.proxy.sessionId,this.ctrl.proxy.sessionId],error:null});
}
}else if(obj.method == "mining.authorize"){
logger.log ( "New peer connected : " + chalk.blueBright(obj.params[0]));
this.name = obj.params[0];
if(this.ctrl.proxy.status != "ready"){
this.Error("Proxy not authorised yet");
}else{

logger.log ( this.ctrl.miners.size + " peer(s) mining on this proxy");
this.send({id:this.lastReqId,result:true,error:null});
this.send({id:null,method:"mining.set_target", params:this.ctrl.proxy.last_target});
this.send({id:null,method:"mining.notify", params:this.ctrl.proxy.last_notif});
}
} else if(obj.method == "mining.submit"){
this.status = "submit";
obj.params[0] = config.wallet;
if(config.enable_worker_id){
obj.params[0] = obj.params[0] + "." + this.name;
}
logger.log ( "Submit work for " + this.name);
this.ctrl.proxy.submit(this.id,obj);
}
} else if(obj.method == "mining.submit"){
this.status = "submit";
obj.params[0] = config.wallet;
if(config.enable_worker_id){
obj.params[0] = obj.params[0] + "." + this.name;
}
logger.log ( "Submit work for " + this.name);
this.ctrl.proxy.submit(this.id,obj);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand All @@ -127,6 +145,26 @@ Miner.prototype.onEnd = function() {
logger.log ( this.ctrl.miners.size + " peer(s) mining on this proxy");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Miner.prototype.onRejected = function() {
this.ctrl.totalRejectedShares++;
this.rejectedShares++;
if(this.ctrl.totalRejectedShares >= config.on_rejected_share.threshold ){
this.ctrl.outputRegSharesStats();
if(config.on_rejected_share != null){
switch(config.on_rejected_share.strategy){
case "restart":
this.ctrl.proxy.reset();
break;
case "kill":
process.exit(1);
break;
default: // NOP
break;
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Miner.prototype.send = function(data) {
logger.dbg('[MINER<'+this.id+'>:OUT] ',data);
if (data.method && data.method == 'mining.notify' ) {
Expand All @@ -152,8 +190,10 @@ Miner.prototype.send = function(data) {
} else if (data.error && data.error.length > 1) {
// error is returned from some pools and not others
logger.log("Work from " + this.name + " " + chalk.red("rejected: " + data.error[1]));
this.onRejected(); return;
} else {
logger.log("Work from " + this.name + " " + chalk.red("rejected"));
this.onRejected(); return;
}
}
if (this.connection && !(this.connection.destroyed)) {
Expand Down
95 changes: 51 additions & 44 deletions lib/pool_connector.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ var PoolConnector = function(restartCallback){
logger.warn('Resetting workers...');
this.miners.reset();
}else{
this.miners = new minersController.MinersController(this);
logger.warn('Creating workers listner...');
this.miners = new minersController.MinersController(this);
}
// Subscribe to pool
logger.log('Subscribing to pool...');
Expand All @@ -50,49 +51,53 @@ var PoolConnector = function(restartCallback){
this.onData = function(obj) {
logger.dbg('====================================')
logger.dbg('[POOL:IN] ' + JSON.stringify(obj));
if (this.status == 'subscribing' && (obj.id == 1)) { // Subscription (internal)
if(obj.error){
this.error(obj.error);
}else{
this.sessionId = obj.result[1];
logger.log('Stratum session id ' + this.sessionId);
var auth = { id: 2
, method: "mining.authorize"
, params: [ config.wallet + "." + config.proxy_name
, config.password ]
};
logger.log('Authorizing mining wallet '+ config.wallet);
this.status = "authorizing";
this.send(auth);
}
} else if (this.status == 'authorizing' && (obj.id == 2)) { // Authorization (internal)
if (obj.error) {
this.error(obj.error);
} else if (obj.result) {
this.status = 'ready';
logger.log('Mining wallet ' + config.wallet + chalk.green(' authorization granted') );
var xtra = { id: 3
, method: "mining.extranonce.subscribe"
, params:[]
if(this.poolSocket != null){
if (this.status == 'subscribing' && (obj.id == 1)) { // Subscription (internal)
if(obj.error){
this.error(obj.error);
}else{
this.sessionId = obj.result[1];
logger.log('Stratum session id ' + this.sessionId);
var auth = { id: 2
, method: "mining.authorize"
, params: [ config.wallet + "." + config.proxy_name
, config.password ]
};
logger.log('Authorizing mining wallet '+ config.wallet);
this.status = "authorizing";
this.send(auth);
}
} else if (this.status == 'authorizing' && (obj.id == 2)) { // Authorization (internal)
if (obj.error) {
this.error(obj.error);
} else if (obj.result) {
this.status = 'ready';
logger.log('Mining wallet ' + config.wallet + chalk.green(' authorization granted') );
var xtra = { id: 3
, method: "mining.extranonce.subscribe"
, params:[]
}
this.send(xtra);
} else {
logger.log('Mining wallet ' + config.wallet + chalk.red(' authorization failed') );
}
this.send(xtra);
} else {
logger.log('Mining wallet ' + config.wallet + chalk.red(' authorization failed') );
}
} else {
if (obj.method === 'mining.notify' || obj.method === 'mining.set_target') {
// Broadcast to all miners
this.miners.broadcastToMiners(obj);
if (obj.method === 'mining.notify') {
logger.log('New work : ' + obj.params[3]);
this.last_notif = obj.params;
} else if (obj.method === 'mining.set_target') {
this.last_target = obj.params;
logger.log('New target : ' + obj.params[0]);
if (obj.method === 'mining.notify' || obj.method === 'mining.set_target') {
if (obj.method === 'mining.notify') {
logger.log('New work : ' + obj.params[3]);
this.last_notif = obj.params;
} else if (obj.method === 'mining.set_target') {
this.last_target = obj.params;
logger.log('New target : ' + obj.params[0]);
}
// Broadcast to all miners
this.miners.broadcastToMiners(obj);
} else { //Forward message to the correct miner
this.miners.sendToMiner(obj.id, obj);
}
} else { //Forward message to the correct miner
this.miners.sendToMiner(obj.id, obj);
}
}else{
logger.dbg('[POOL:IN] IGNORED');
}
logger.dbg('====================================')
};
Expand Down Expand Up @@ -165,10 +170,12 @@ var PoolConnector = function(restartCallback){
}

this.reset = function () {
logger.err('Closing all connections...');
this.destroy();
logger.err("Waiting 10 seconds before attempting to restart the Stratum Proxy");
setTimeout( () => { restartCallback(); },10000);
if(this.poolSocket){
logger.err('Closing all connections...');
this.destroy();
logger.err("Waiting "+ config.restart_delay+" seconds before attempting to restart the Stratum Proxy");
setTimeout( () => { restartCallback(); },config.restart_delay * 1000);
}
}

// - - - START - - - //
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zecproxy",
"version": "1.0.6",
"version": "1.0.7",
"description": "Zcash Stratum Proxy",
"main": "proxy.js",
"scripts": {},
Expand Down

0 comments on commit 6b93a81

Please sign in to comment.