Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CoinFoudry improvements #38

Open
wants to merge 46 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d57fd37
Initial
Dec 18, 2017
8282c75
Add missing logging proxy funcs
Dec 18, 2017
50dadc8
WIP
Dec 18, 2017
b34da76
vscode
Dec 18, 2017
45237a6
Fixed logging
Dec 21, 2017
ea2a880
Fix blockReward
Dec 21, 2017
ade97fe
ZMQ connect
Jan 11, 2018
b87ea3c
revert
Jan 12, 2018
f8097e2
ZMQ block monitoring
Jan 14, 2018
d2d3b3d
Fix
Jan 14, 2018
005d09b
Logging
Jan 20, 2018
df23de4
SSL/TLS
Jan 24, 2018
280c8cf
WIP
Jan 25, 2018
20102ff
Merge branch 'master' of https://github.com/coinfoundry/z-node-stratu…
Jan 25, 2018
28b7f28
share source
Mar 1, 2018
b93075f
publisher connect
Mar 2, 2018
a8b5317
BTCP adjustments
Mar 4, 2018
99e66c7
configurable zmq blocknotify topic
Mar 4, 2018
8fdac9d
Fix target encoding not obeying coin config
Mar 5, 2018
749080e
Fix
Mar 5, 2018
711b677
WIP
Mar 5, 2018
f2a7c8f
WIP
Mar 5, 2018
3f0e70d
tx comment
Mar 6, 2018
8c878c3
Merge branch 'master' of https://github.com/coinfoundry/z-node-stratu…
Mar 6, 2018
a3f118b
WIP
Mar 6, 2018
0aa3b3c
Add payload-type-flag-frame to share publisher
Mar 15, 2018
ddeaec1
protobuf publish support
Apr 6, 2018
22431cf
WIP
Apr 6, 2018
ea71da6
SSL RPC support
Apr 6, 2018
87ef541
Fix
Apr 6, 2018
1857677
FreeBSD
Apr 6, 2018
2553536
zeromq
Apr 6, 2018
77d3f8d
Exit on startup error
Apr 12, 2018
47d76b8
http request error handling
Apr 17, 2018
609437f
Support for btStream
Apr 19, 2018
b704763
lastJobRefresh = now;
Apr 19, 2018
46dbf8f
Fix
Apr 19, 2018
8ba833f
ZMQ
Apr 22, 2018
3eb3111
WIP
Apr 23, 2018
5bc3608
Code style
Apr 29, 2018
bc7e9d6
Switch endianess for flags
Sep 22, 2018
f544bee
Support for btStream on Curve
Oct 2, 2018
b4eb5ed
WIP
Oct 2, 2018
c022157
WIP
Oct 2, 2018
9709e88
Implement static diff
Oct 4, 2018
2733947
curve
Oct 4, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
.idea/
.idea/
/.vscode/last.sql
/.vscode/temp.sql
1 change: 1 addition & 0 deletions .vscode/database.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach",
"type": "node",
"request": "attach",
"port": 9229,
"outFiles": [],
"localRoot": "${workspaceRoot}",
"remoteRoot": "/mnt/c/Users/${env:USERNAME}/Projects/${workspaceRootFolderName}/"
}]
}
11 changes: 9 additions & 2 deletions lib/algoProperties.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
var ev = require('equihashverify');
var util = require('./util.js');

var diff1 = global.diff1 = 0x0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

var algos = module.exports = global.algos = {
sha256: {
//Uncomment diff if you want to use hardcoded truncated diff
Expand All @@ -21,6 +19,15 @@ var algos = module.exports = global.algos = {
return ev.verify.apply(this, arguments);
}
}
},
'equihash-btcp': {
multiplier: 1,
diff: parseInt('0x0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'),
hash: function(){
return function(){
return ev.verify.apply(this, arguments);
}
}
}
};

Expand Down
10 changes: 5 additions & 5 deletions lib/blockTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var util = require('./util.js');
* The BlockTemplate class holds a single job.
* and provides several methods to validate and submit it to the daemon coin
**/
var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, extraNoncePlaceholder, reward, recipients, poolAddress, payFoundersReward, percentFoundersReward, maxFoundersRewardBlockHeight, foundersRewardAddressChangeInterval, vFoundersRewardAddress, percentTreasuryReward, treasuryRewardStartBlockHeight, treasuryRewardAddressChangeInterval, vTreasuryRewardAddress){
var BlockTemplate = module.exports = function BlockTemplate(jobId, diff1, rpcData, extraNoncePlaceholder, reward, recipients, poolAddress, payFoundersReward, percentFoundersReward, maxFoundersRewardBlockHeight, foundersRewardAddressChangeInterval, vFoundersRewardAddress, percentTreasuryReward, treasuryRewardStartBlockHeight, treasuryRewardAddressChangeInterval, vTreasuryRewardAddress){

//private members
var submits = [];
Expand All @@ -31,7 +31,7 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, extr
blockReward = (this.rpcData.miner + this.rpcData.founders) * 100000000;
}
}

var fees = [];
rpcData.transactions.forEach(function(value) {
fees.push(value);
Expand All @@ -40,7 +40,7 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, extr
rpcData.rewardFees = this.rewardFees;

if (typeof this.genTx === 'undefined') {
this.genTx = transactions.createGeneration(rpcData.height, blockReward, this.rewardFees, recipients, poolAddress, payFoundersReward, percentFoundersReward, maxFoundersRewardBlockHeight, foundersRewardAddressChangeInterval, vFoundersRewardAddress, percentTreasuryReward, treasuryRewardStartBlockHeight, treasuryRewardAddressChangeInterval, vTreasuryRewardAddress).toString('hex');
this.genTx = transactions.createGeneration(rpcData, blockReward, this.rewardFees, recipients, poolAddress, payFoundersReward, percentFoundersReward, maxFoundersRewardBlockHeight, foundersRewardAddressChangeInterval, vFoundersRewardAddress, percentTreasuryReward, treasuryRewardStartBlockHeight, treasuryRewardAddressChangeInterval, vTreasuryRewardAddress).toString('hex');
this.genTxHash = transactions.txHash();

/*
Expand Down Expand Up @@ -87,14 +87,14 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, extr
if (Math.abs(txCount.length % 2) == 1) {
txCount = "0" + txCount;
}

if (this.txCount <= 0x7f){
var varInt = new Buffer(txCount, 'hex');
}
else if (this.txCount <= 0x7fff){
var varInt = new Buffer.concat([Buffer('FD', 'hex'), new Buffer(txCount, 'hex')]);
}

buf = new Buffer.concat([
header,
soln,
Expand Down
17 changes: 13 additions & 4 deletions lib/daemon.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var http = require('http');
var https = require('https');
var cp = require('child_process');
var events = require('events');

Expand Down Expand Up @@ -51,14 +52,19 @@ function DaemonInterface(daemons, logger) {
function performHttpRequest(instance, jsonData, callback) {
var options = {
hostname: (typeof(instance.host) === 'undefined' ? '127.0.0.1' : instance.host),
port: instance.port,
port : instance.port,
path : instance.httpPath,
method: 'POST',
auth: instance.user + ':' + instance.password,
headers: {
'Content-Length': jsonData.length
}
};

if(instance.ssl && !instance.validateCert) {
options.rejectUnauthorized = false;
}

var parseJson = function (res, data) {
var dataJson;

Expand All @@ -69,7 +75,9 @@ function DaemonInterface(daemons, logger) {

try {
dataJson = JSON.parse(data);
callback(dataJson.error, dataJson, data);
}

catch (e) {
if (data.indexOf(':-nan') !== -1) {
data = data.replace(/:-nan,/g, ":0");
Expand All @@ -80,12 +88,13 @@ function DaemonInterface(daemons, logger) {
+ '\nRequest Data: ' + jsonData
+ '\nReponse Data: ' + data);

callback('Could not parse rpc data from daemon instance ' + instance.index, {}, data);
}
if (dataJson)
callback(dataJson.error, dataJson, data);
};

var req = http.request(options, function (res) {
const client = instance.ssl ? https : http;

var req = client.request(options, function(res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
Expand Down
138 changes: 131 additions & 7 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,140 @@
var net = require('net');
var events = require('events');
const net = require('net');
const events = require('events');
const zmq = require('zeromq');
const protobuf = require("protobufjs");

//Gives us global access to everything we need for each hashing algorithm
require('./algoProperties.js');

var pool = require('./pool.js');
const pool_proto = require('./pool.js');

exports.daemon = require('./daemon.js');
exports.varDiff = require('./varDiff.js');

// validate args
if(process.argv.length < 3) {
console.log("Error: Config file argument required. Good bye ..");
process.exit(1);
}

exports.createPool = function (poolOptions, authorizeFn) {
var newPool = new pool(poolOptions, authorizeFn);
const createPool = function (poolOptions, authorizeFn) {
var newPool = new pool_proto(poolOptions, authorizeFn);
return newPool;
};

// load config
var config = require(process.argv[2]);

// create pool
const pool = createPool(config, function (ip, port, workerName, password, callback) { //stratum authorization function
console.log("Authorize " + workerName + ":" + password + "@" + ip);

var minerWorker = workerName.split(".");
var miner = minerWorker[0].trim();
var worker = minerWorker.length > 1 ? minerWorker[1].trim() : "";

if(config.authWhiteList && config.authWhiteList.hasOwnProperty(miner)) {
console.log("Authorizing white-listed miner " + miner + " as " + config.authWhiteList[miner]);
callback({ authorized: true, workerNameOverride: config.authWhiteList[miner] });
return;
}

pool.daemon.cmd('validateaddress', [miner], function (results) {
var authResult = {};

authResult.authorized = results.filter(function (r) {
return r.response.isvalid
}).length > 0;

authResult.disconnect = !authResult.authorized;

callback(authResult);
});
});

pool.on('log', function (severity, logText) {
console.log(severity + ': ' + logText);
});

// Define proto message
const ShareMessage = !!!config.publisherJson ?
new protobuf.Type("ShareMessage")
.add(new protobuf.Field("poolId", 1, "string"))
.add(new protobuf.Field("miner", 2, "string"))
.add(new protobuf.Field("worker", 3, "string"))
.add(new protobuf.Field("payoutInfo", 4, "string"))
.add(new protobuf.Field("userAgent", 5, "string"))
.add(new protobuf.Field("ipAddress", 6, "string"))
.add(new protobuf.Field("source", 7, "string"))
.add(new protobuf.Field("difficulty", 8, "double"))
.add(new protobuf.Field("blockHeight", 9, "int64"))
.add(new protobuf.Field("blockReward", 10, "double"))
.add(new protobuf.Field("blockHash", 11, "string"))
.add(new protobuf.Field("isBlockCandidate", 12, "bool"))
.add(new protobuf.Field("transactionConfirmationData", 13, "string"))
.add(new protobuf.Field("networkDifficulty", 14, "double")) : undefined;

// connect/bind ZMQ share publisher socket
const sock = zmq.socket('pub');
const pubFlags = config.publisherJson ? 1 : 2; // WireFormat.Json or WireFormat.ProtoBuf
const pubFlagsBuf = Buffer.allocUnsafe(4);
pubFlagsBuf.writeUInt32BE(pubFlags, 0);

if(config.publisherRawServerSecret) {
sock.curve_secretkey = new Buffer(config.publisherRawServerSecret, "hex");
sock.curve_server = 1;

pool.emitInfoLog('Enabled ZMQ Curve server mode');
}

if(!config.publisherConnect) {
sock.bindSync(config.publisherSocket);
pool.emitInfoLog('Bound to ZMQ publisher socket ' + config.publisherSocket);
} else {
sock.connect(config.publisherSocket);
pool.emitInfoLog('Connected to ZMQ publisher socket ' + config.publisherSocket);
}

// monitor shares
pool.on('share', function (isValidShare, isValidBlock, data) {
if (isValidBlock)
pool.emitInfoLog('Pool ' + config.publisherTopic + ' found block ' + data.height);
// else if (isValidShare)
// pool.emitInfoLog('Valid share submitted');
else if (data.blockHash)
pool.emitInfoLog('We thought a block was found but it was rejected by the daemon');
else if(!isValidShare)
pool.emitInfoLog('Invalid share submitted')

if(isValidShare) {
var minerWorker = data.worker.split(".");

// sanitize inputs
var miner = minerWorker[0].trim();
var worker = minerWorker.length > 1 ? minerWorker[1].trim() : "";

// transform it
var share = {
difficulty: data.difficulty,
networkDifficulty: data.blockDiff,
blockHeight: data.height,
blockReward: data.blockReward / 100000000,
miner: miner,
worker: worker,
ipAddress: data.ip,
isBlockCandidate: isValidBlock,
blockHex: data.blockHex,
blockHash: data.blockHash,
transactionConfirmationData: data.txHash,
userAgent: '',
payoutInfo: '', // monero only
source: config.clusterName
};

const rawMsg = config.publisherJson ? JSON.stringify(share) :
Buffer.from(ShareMessage.encode(ShareMessage.create(share)).finish());

// publish
sock.send([config.publisherTopic, pubFlagsBuf, rawMsg]);
}
});

pool.start();
7 changes: 5 additions & 2 deletions lib/jobManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ var JobManager = module.exports = function JobManager(options) {
this.currentJob;
this.validJobs = {};

var diff1 = algos[options.coin.algorithm].diff;
var hashDigest = algos[options.coin.algorithm].hash(options.coin);

var coinbaseHasher = (function () {
Expand All @@ -106,6 +107,7 @@ var JobManager = module.exports = function JobManager(options) {
this.updateCurrentJob = function (rpcData) {
var tmpBlockTemplate = new blockTemplate(
jobCounter.next(),
diff1,
rpcData,
_this.extraNoncePlaceholder,
options.coin.reward,
Expand Down Expand Up @@ -149,6 +151,7 @@ var JobManager = module.exports = function JobManager(options) {

var tmpBlockTemplate = new blockTemplate(
jobCounter.next(),
diff1,
rpcData,
_this.extraNoncePlaceholder,
options.coin.reward,
Expand Down Expand Up @@ -212,7 +215,7 @@ var JobManager = module.exports = function JobManager(options) {
if (soln.length !== 2694) {
return shareError([20, 'incorrect size of solution']);
}

if (!isHexString(extraNonce2)) {
return shareError([20, 'invalid hex in extraNonce2']);
}
Expand Down Expand Up @@ -285,7 +288,7 @@ var JobManager = module.exports = function JobManager(options) {
port: port,
worker: workerName,
height: job.rpcData.height,
blockReward: job.rpcData.reward,
blockReward: job.rpcData.rewardToPool,
difficulty: difficulty,
shareDiff: shareDiff.toFixed(8),
blockDiff: blockDiffAdjusted,
Expand Down
Loading