2015-01-03 11:29:22 +01:00
|
|
|
/**
|
|
|
|
* Node.js implementation of platform-specific routines.
|
|
|
|
*/
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2015-01-09 22:36:42 +01:00
|
|
|
var os = require("os");
|
2015-01-03 11:29:22 +01:00
|
|
|
var crypto = require("crypto");
|
2015-01-09 22:36:42 +01:00
|
|
|
var promise = typeof Promise === "undefined" ?
|
|
|
|
require("es6-promise").Promise :
|
|
|
|
Promise;
|
2015-01-07 22:28:13 +01:00
|
|
|
var bignum = require("bignum");
|
|
|
|
var assert = require("./util").assert;
|
2015-01-09 22:36:42 +01:00
|
|
|
var worker = require("./worker");
|
2015-01-07 22:28:13 +01:00
|
|
|
|
2015-01-03 15:52:27 +01:00
|
|
|
var createHash = crypto.createHash;
|
2015-01-03 11:29:22 +01:00
|
|
|
|
|
|
|
exports.sha512 = function(buf) {
|
2015-01-03 15:52:27 +01:00
|
|
|
return createHash("sha512").update(buf).digest();
|
2015-01-03 11:29:22 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.sha256 = function(buf) {
|
2015-01-03 15:52:27 +01:00
|
|
|
return createHash("sha256").update(buf).digest();
|
2015-01-03 11:29:22 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.ripemd160 = function(buf) {
|
2015-01-03 15:52:27 +01:00
|
|
|
return createHash("ripemd160").update(buf).digest();
|
2015-01-03 11:29:22 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.randomBytes = crypto.randomBytes;
|
2015-01-07 22:28:13 +01:00
|
|
|
|
|
|
|
// 2^64.
|
|
|
|
var B64 = bignum("18446744073709551616");
|
|
|
|
|
|
|
|
// NOTE(Kagami): We can't calculate entire target in JavaScript but the
|
|
|
|
// result can be represented in native number type without losing
|
|
|
|
// precision (targets mainly much less than 2^53).
|
|
|
|
exports.getTarget = function(opts) {
|
|
|
|
// Calculate it bottom-up, right-to-left.
|
|
|
|
var length = bignum(opts.payloadLength)
|
|
|
|
// To account for the nonce which we will append later.
|
|
|
|
.add(8)
|
|
|
|
.add(opts.payloadLengthExtraBytes);
|
|
|
|
var denominator = bignum(opts.ttl)
|
|
|
|
.mul(length)
|
|
|
|
.div(65536)
|
|
|
|
.add(length)
|
|
|
|
.mul(opts.nonceTrialsPerByte);
|
|
|
|
var target = B64.div(denominator).toNumber();
|
|
|
|
assert(target <= 9007199254740991, "Unsafe target");
|
|
|
|
return target;
|
|
|
|
};
|
2015-01-09 22:36:42 +01:00
|
|
|
|
2015-01-10 14:03:14 +01:00
|
|
|
exports.pow = function(opts) {
|
2015-01-09 22:36:42 +01:00
|
|
|
var poolSize = opts.poolSize || os.cpus().length;
|
|
|
|
|
|
|
|
// Check all input params prematurely to not let promise executor or
|
|
|
|
// worker to fail because of it.
|
2015-01-11 03:59:32 +01:00
|
|
|
assert(typeof poolSize === "number", "Bad pool size");
|
|
|
|
assert(poolSize >= 1, "Pool size is too low");
|
|
|
|
assert(poolSize <= 1024, "Pool size is too high");
|
2015-01-09 22:36:42 +01:00
|
|
|
assert(typeof opts.target === "number", "Bad target");
|
|
|
|
assert(opts.target >= 0, "Target is too low");
|
|
|
|
assert(opts.target <= 9007199254740991, "Target is too high");
|
|
|
|
assert(Buffer.isBuffer(opts.initialHash), "Bad initial hash");
|
2015-01-11 03:59:32 +01:00
|
|
|
assert(opts.initialHash.length === 64, "Bad initial hash");
|
2015-01-09 22:36:42 +01:00
|
|
|
|
|
|
|
// TODO(Kagami): Allow to cancel a POW (see `platform.browser.js`).
|
|
|
|
return new promise(function(resolve, reject) {
|
|
|
|
worker.powAsync(
|
|
|
|
poolSize,
|
|
|
|
opts.target,
|
|
|
|
opts.initialHash,
|
|
|
|
function(err, nonce) {
|
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve(nonce);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
};
|