Merge remote-tracking branch 'matiu/feature/Block-test'
Conflicts: util/util.js
This commit is contained in:
commit
fa47ee9984
297
Block.js
297
Block.js
|
@ -93,15 +93,11 @@ Block.prototype.checkProofOfWork = function checkProofOfWork() {
|
|||
|
||||
// TODO: Create a compare method in node-buffertools that uses the correct
|
||||
// endian so we don't have to reverse both buffers before comparing.
|
||||
buffertools.reverse(this.hash);
|
||||
|
||||
if (buffertools.compare(this.hash, target) > 0) {
|
||||
var reverseHash = buffertools.reverse(this.hash);
|
||||
if (buffertools.compare(reverseHash, target) > 0) {
|
||||
throw new VerificationError('Difficulty target not met');
|
||||
}
|
||||
|
||||
// Return the hash to its normal order
|
||||
buffertools.reverse(this.hash);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -199,7 +195,7 @@ Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) {
|
|||
throw new VerificationError('No merkle root');
|
||||
}
|
||||
|
||||
if (buffertools.compare(this.calcMerkleRoot(), this.merkle_root) == 0) {
|
||||
if (buffertools.compare(this.calcMerkleRoot(txs), new Buffer(this.merkle_root)) !== 0) {
|
||||
throw new VerificationError('Merkle root incorrect');
|
||||
}
|
||||
|
||||
|
@ -236,214 +232,6 @@ Block.prototype.toString = function toString() {
|
|||
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes some properties based on information from the parent block.
|
||||
*/
|
||||
Block.prototype.attachTo = function attachTo(parent) {
|
||||
this.height = parent.height + 1;
|
||||
this.setChainWork(parent.getChainWork().add(this.getWork()));
|
||||
};
|
||||
|
||||
Block.prototype.setChainWork = function setChainWork(chainWork) {
|
||||
if (Buffer.isBuffer(chainWork)) {
|
||||
// Nothing to do
|
||||
} else if ("function" === typeof chainWork.toBuffer) { // duck-typing bignum
|
||||
chainWork = chainWork.toBuffer();
|
||||
} else {
|
||||
throw new Error("Block.setChainWork(): Invalid datatype");
|
||||
}
|
||||
|
||||
this.chainWork = chainWork;
|
||||
};
|
||||
|
||||
Block.prototype.getChainWork = function getChainWork() {
|
||||
return Bignum.fromBuffer(this.chainWork);
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares the chainWork of two blocks.
|
||||
*/
|
||||
Block.prototype.moreWorkThan = function moreWorkThan(otherBlock) {
|
||||
return this.getChainWork().cmp(otherBlock.getChainWork()) > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the difficulty target for the next block after this one.
|
||||
*/
|
||||
Block.prototype.getNextWork =
|
||||
function getNextWork(blockChain, nextBlock, callback) {
|
||||
var self = this;
|
||||
|
||||
var powLimit = blockChain.getMinDiff();
|
||||
var powLimitTarget = util.decodeDiffBits(powLimit, true);
|
||||
|
||||
var targetTimespan = blockChain.getTargetTimespan();
|
||||
var targetSpacing = blockChain.getTargetSpacing();
|
||||
var interval = targetTimespan / targetSpacing;
|
||||
|
||||
if (this.height == 0) {
|
||||
callback(null, this.bits);
|
||||
}
|
||||
|
||||
if ((this.height+1) % interval !== 0) {
|
||||
if (blockChain.isTestnet()) {
|
||||
// Special testnet difficulty rules
|
||||
var lastBlock = blockChain.getTopBlock();
|
||||
|
||||
// If the new block's timestamp is more than 2 * 10 minutes
|
||||
// then allow mining of a min-difficulty block.
|
||||
if (nextBlock.timestamp > this.timestamp + targetSpacing*2) {
|
||||
callback(null, powLimit);
|
||||
} else {
|
||||
// Return last non-"special-min-difficulty" block
|
||||
if (this.bits != powLimit) {
|
||||
// Current block is non-min-diff
|
||||
callback(null, this.bits);
|
||||
} else {
|
||||
// Recurse backwards until a non min-diff block is found.
|
||||
function lookForLastNonMinDiff(block, callback) {
|
||||
try {
|
||||
if (block.height > 0 &&
|
||||
block.height % interval !== 0 &&
|
||||
block.bits == powLimit) {
|
||||
blockChain.getBlockByHeight(
|
||||
block.height - 1,
|
||||
function (err, lastBlock) {
|
||||
try {
|
||||
if (err) throw err;
|
||||
lookForLastNonMinDiff(lastBlock, callback);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
callback(null, block.bits);
|
||||
}
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
lookForLastNonMinDiff(this, callback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not adjustment interval, next block has same difficulty
|
||||
callback(null, this.bits);
|
||||
}
|
||||
} else {
|
||||
// Get the first block from the old difficulty period
|
||||
blockChain.getBlockByHeight(
|
||||
this.height - interval + 1,
|
||||
function (err, lastBlock) {
|
||||
try {
|
||||
if (err) throw err;
|
||||
|
||||
// Determine how long the difficulty period really took
|
||||
var actualTimespan = self.timestamp - lastBlock.timestamp;
|
||||
|
||||
// There are some limits to how much we will adjust the difficulty in
|
||||
// one step
|
||||
if (actualTimespan < targetTimespan/4) {
|
||||
actualTimespan = targetTimespan/4;
|
||||
}
|
||||
if (actualTimespan > targetTimespan*4) {
|
||||
actualTimespan = targetTimespan*4;
|
||||
}
|
||||
|
||||
var oldTarget = util.decodeDiffBits(self.bits, true);
|
||||
var newTarget = oldTarget.mul(actualTimespan).div(targetTimespan);
|
||||
|
||||
if (newTarget.cmp(powLimitTarget) > 0) {
|
||||
newTarget = powLimitTarget;
|
||||
}
|
||||
|
||||
Debug1('Difficulty retarget (target='+targetTimespan +
|
||||
', actual='+actualTimespan+')');
|
||||
Debug1('Before: '+oldTarget.toBuffer().toString('hex'));
|
||||
Debug1('After: '+newTarget.toBuffer().toString('hex'));
|
||||
|
||||
callback(null, util.encodeDiffBits(newTarget));
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var medianTimeSpan = 11;
|
||||
|
||||
Block.prototype.getMedianTimePast =
|
||||
function getMedianTimePast(blockChain, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
Step(
|
||||
function getBlocks() {
|
||||
var heights = [];
|
||||
for (var i = 0, m = medianTimeSpan; i < m && (self.height - i) >= 0; i++) {
|
||||
heights.push(self.height - i);
|
||||
}
|
||||
blockChain.getBlocksByHeights(heights, this);
|
||||
},
|
||||
function calcMedian(err, blocks) {
|
||||
if (err) throw err;
|
||||
|
||||
var timestamps = blocks.map(function (block) {
|
||||
if (!block) {
|
||||
throw new Error("Prior block missing, cannot calculate median time");
|
||||
}
|
||||
|
||||
return +block.timestamp;
|
||||
});
|
||||
|
||||
// Sort timestamps
|
||||
timestamps = timestamps.sort();
|
||||
|
||||
// Return median timestamp
|
||||
this(null, timestamps[Math.floor(timestamps.length/2)]);
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
Block.prototype.verifyChild =
|
||||
function verifyChild(blockChain, child, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
Step(
|
||||
function getExpectedDifficulty() {
|
||||
self.getNextWork(blockChain, child, this);
|
||||
},
|
||||
function verifyExpectedDifficulty(err, nextWork) {
|
||||
if (err) throw err;
|
||||
|
||||
if (+child.bits !== +nextWork) {
|
||||
throw new VerificationError("Incorrect proof of work '"+child.bits+"',"+
|
||||
" should be '"+nextWork+"'.");
|
||||
}
|
||||
|
||||
this();
|
||||
},
|
||||
function getMinimumTimestamp(err) {
|
||||
if (err) throw err;
|
||||
|
||||
self.getMedianTimePast(blockChain, this);
|
||||
},
|
||||
function verifyTimestamp(err, medianTimePast) {
|
||||
if (err) throw err;
|
||||
|
||||
if (child.timestamp <= medianTimePast) {
|
||||
throw new VerificationError("Block's timestamp is too early");
|
||||
}
|
||||
|
||||
this();
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
Block.prototype.createCoinbaseTx =
|
||||
function createCoinbaseTx(beneficiary)
|
||||
|
@ -461,85 +249,6 @@ function createCoinbaseTx(beneficiary)
|
|||
return tx;
|
||||
};
|
||||
|
||||
Block.prototype.prepareNextBlock =
|
||||
function prepareNextBlock(blockChain, beneficiary, time, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var newBlock = new Block();
|
||||
Step(
|
||||
function getMedianTimePastStep() {
|
||||
self.getMedianTimePast(blockChain, this);
|
||||
},
|
||||
|
||||
function getNextWorkStep(err, medianTimePast) {
|
||||
if (err) throw err;
|
||||
|
||||
if (!time) {
|
||||
// TODO: Use getAdjustedTime for the second timestamp
|
||||
time = Math.max(medianTimePast+1,
|
||||
Math.floor(new Date().getTime() / 1000));
|
||||
}
|
||||
|
||||
self.getNextWork(blockChain, newBlock, this);
|
||||
},
|
||||
|
||||
function applyNextWorkStep(err, nextWork) {
|
||||
if (err) throw err;
|
||||
newBlock.bits = nextWork;
|
||||
this(null);
|
||||
},
|
||||
|
||||
function miscStep(err) {
|
||||
if (err) throw err;
|
||||
|
||||
newBlock.version = 1;
|
||||
newBlock.timestamp = time;
|
||||
newBlock.prev_hash = self.getHash().slice(0);
|
||||
newBlock.height = self.height+1;
|
||||
|
||||
// Create coinbase transaction
|
||||
var txs = [];
|
||||
|
||||
var tx = newBlock.createCoinbaseTx(beneficiary);
|
||||
txs.push(tx);
|
||||
|
||||
newBlock.merkle_root = newBlock.calcMerkleRoot(txs);
|
||||
|
||||
// Return reference to (unfinished) block
|
||||
this(null, {block: newBlock, txs: txs});
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
Block.prototype.mineNextBlock =
|
||||
function mineNextBlock(blockChain, beneficiary, time, miner, callback)
|
||||
{
|
||||
this.prepareNextBlock(blockChain, beneficiary, time, function (err, data) {
|
||||
try {
|
||||
if (err) throw err;
|
||||
|
||||
var newBlock = data.block;
|
||||
var txs = data.txs;
|
||||
|
||||
newBlock.solve(miner, function (err, nonce) {
|
||||
newBlock.nonce = nonce;
|
||||
|
||||
// Make sure hash is cached
|
||||
newBlock.getHash();
|
||||
|
||||
callback(err, newBlock, txs);
|
||||
});
|
||||
|
||||
// Return reference to (unfinished) block
|
||||
return newBlock;
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Block.prototype.solve = function solve(miner, callback) {
|
||||
var header = this.getHeader();
|
||||
var target = util.decodeDiffBits(this.bits);
|
||||
|
|
|
@ -16,7 +16,8 @@ module.exports = function(grunt) {
|
|||
stdout: true,
|
||||
stderr: true
|
||||
},
|
||||
command: 'node ./browser/build.js -a',
|
||||
command: grunt.option('target') === 'dev' ?
|
||||
'node ./browser/build.js -a -d ' : 'node ./browser/build.js -a'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -18,6 +18,8 @@ var PrivateKey = imports.PrivateKey || require('./PrivateKey');
|
|||
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
|
||||
var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
|
||||
|
||||
Transaction.COINBASE_OP = COINBASE_OP;
|
||||
|
||||
function TransactionIn(data) {
|
||||
if ("object" !== typeof data) {
|
||||
data = {};
|
||||
|
@ -43,7 +45,10 @@ TransactionIn.prototype.getScript = function getScript() {
|
|||
};
|
||||
|
||||
TransactionIn.prototype.isCoinBase = function isCoinBase() {
|
||||
return buffertools.compare(this.o, COINBASE_OP) === 0;
|
||||
if (!this.o) return false;
|
||||
|
||||
//The new Buffer is for Firefox compatibility
|
||||
return buffertools.compare(new Buffer(this.o), COINBASE_OP) === 0;
|
||||
};
|
||||
|
||||
TransactionIn.prototype.serialize = function serialize() {
|
||||
|
|
|
@ -21,6 +21,7 @@ requireWhenAccessed('networks', './networks');
|
|||
requireWhenAccessed('util', './util/util');
|
||||
requireWhenAccessed('EncodedData', './util/EncodedData');
|
||||
requireWhenAccessed('VersionedData', './util/VersionedData');
|
||||
requireWhenAccessed('BinaryParser', './util/BinaryParser');
|
||||
requireWhenAccessed('Address', './Address');
|
||||
requireWhenAccessed('Opcode', './Opcode');
|
||||
requireWhenAccessed('Script', './Script');
|
||||
|
|
|
@ -52,6 +52,7 @@ var modules = [
|
|||
'util/util',
|
||||
'util/EncodedData',
|
||||
'util/VersionedData',
|
||||
'util/BinaryParser',
|
||||
];
|
||||
|
||||
var createBitcore = function(opts) {
|
||||
|
|
Binary file not shown.
|
@ -4,9 +4,33 @@ var chai = chai || require('chai');
|
|||
var bitcore = bitcore || require('../bitcore');
|
||||
var should = chai.should();
|
||||
|
||||
var testdata = testdata || require('./testdata');
|
||||
var BlockModule = bitcore.Block;
|
||||
var BinaryParser = bitcore.BinaryParser;
|
||||
var Block;
|
||||
|
||||
|
||||
var getBlock = function (onlyHeader) {
|
||||
|
||||
var testnetMagic = bitcore.networks.testnet.magic.toString('hex');
|
||||
|
||||
var b = new Block();
|
||||
// this is block 86756 from testnet3
|
||||
var p = new BinaryParser(testdata.dataRawBlock);
|
||||
|
||||
|
||||
var magic = p.buffer(4).toString('hex');
|
||||
|
||||
|
||||
if (magic !== testnetMagic )
|
||||
throw new Error('CRITICAL ERROR: Magic number mismatch: ' +
|
||||
magic + ' : ' + testnetMagic);
|
||||
|
||||
p.word32le();
|
||||
b.parse(p, onlyHeader);
|
||||
return b;
|
||||
};
|
||||
|
||||
describe('Block', function() {
|
||||
it('should initialze the main object', function() {
|
||||
should.exist(BlockModule);
|
||||
|
@ -16,8 +40,149 @@ describe('Block', function() {
|
|||
should.exist(Block);
|
||||
});
|
||||
it('should be able to create instance', function() {
|
||||
var p = new Block();
|
||||
should.exist(p);
|
||||
var b = new Block();
|
||||
should.exist(b);
|
||||
});
|
||||
|
||||
it('should be able to parse a block from hex', function() {
|
||||
var b = getBlock();
|
||||
should.exist(b);
|
||||
should.exist(b.getHash());
|
||||
});
|
||||
|
||||
it('should be able to check block contents', function() {
|
||||
var b = getBlock();
|
||||
should.exist(b.getHash());
|
||||
b.checkHash().should.equal(true);
|
||||
b.checkProofOfWork().should.equal(true);
|
||||
b.getWork().toString().should.equal('17180131332');
|
||||
b.checkTimestamp().should.equal(true);
|
||||
|
||||
});
|
||||
it('#checkBlock should be able to check block contents', function() {
|
||||
var b = getBlock();
|
||||
should.exist(b.getHash());
|
||||
b.checkBlock().should.equal(true);
|
||||
});
|
||||
|
||||
|
||||
it('should be able to check Transactions', function() {
|
||||
var b = getBlock();
|
||||
|
||||
b.checkTransactions(b.txs).should.equal(true);
|
||||
b.checkTransactions.bind([]).should.throw();
|
||||
|
||||
var coinbase = b.txs.shift;
|
||||
b.checkTransactions.bind(b.txs).should.throw();
|
||||
b.txs.push(coinbase);
|
||||
b.checkTransactions.bind(b.txs).should.throw();
|
||||
|
||||
|
||||
});
|
||||
|
||||
it('should be able to checkMerkleRoot', function() {
|
||||
|
||||
var b = getBlock();
|
||||
b.getMerkleTree(b.txs).length.should.equal(45);
|
||||
bitcore.buffertools.toHex(b.calcMerkleRoot(b.txs)).should.equal(bitcore.buffertools.toHex(new Buffer(b.merkle_root)));
|
||||
|
||||
b.checkMerkleRoot(b.txs);
|
||||
|
||||
delete b['merkle_root'];
|
||||
b.checkMerkleRoot.bind(b.txs).should.throw();
|
||||
|
||||
|
||||
b.merkle_root=new Buffer('wrong');
|
||||
b.checkMerkleRoot.bind(b.txs).should.throw();
|
||||
});
|
||||
|
||||
|
||||
|
||||
it('should be able to checkProofOfWork', function() {
|
||||
var b = getBlock();
|
||||
|
||||
b.hash = bitcore.buffertools.reverse(new Buffer('000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11', 'hex'));
|
||||
b.checkHash().should.equal(true);
|
||||
b.checkProofOfWork().should.equal(true);
|
||||
|
||||
// wrong hash hash, ok proof of work
|
||||
b.hash = bitcore.buffertools.reverse(new Buffer('000000000000016390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11', 'hex'));
|
||||
b.checkProofOfWork().should.equal(true);
|
||||
b.checkHash().should.equal(false);
|
||||
|
||||
|
||||
// wrong hash hash, wrong proof of work
|
||||
b.hash = bitcore.buffertools.reverse(new Buffer('0000000bbb99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11', 'hex'));
|
||||
b.checkHash().should.equal(false);
|
||||
b.checkProofOfWork.bind().should.throw();
|
||||
});
|
||||
|
||||
|
||||
it('should be able to check via checkBlock', function() {
|
||||
var b = getBlock();
|
||||
b.checkBlock.bind(b.txs).should.throw();
|
||||
b.getHash();
|
||||
b.checkBlock(b.txs).should.equal(true);
|
||||
});
|
||||
|
||||
it('should be able to get components from blocks', function() {
|
||||
var b = getBlock(true);
|
||||
|
||||
bitcore.util.formatHashFull(b.getHash()).should.equal('000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11');
|
||||
|
||||
bitcore.util.formatHashFull(b.getHeader()).should.equal('d6383bd51c3fffc051be10ce58e6d52d1eb00470ae1ab4d5a3375c0f51382c6f249fff84e9888286974cfc97000000003c35b5e70b13d5b938fef4e998a977c17bea978390273b7c50a9aa4b00000002');
|
||||
|
||||
bitcore.util.formatHashFull(b.merkle_root).should.equal('58e6d52d1eb00470ae1ab4d5a3375c0f51382c6f249fff84e9888286974cfc97');
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('#getBlockValue should return the correct block value', function() {
|
||||
var c = bitcore.util.COIN;
|
||||
bitcore.Block.getBlockValue(0).div(c).toNumber().should.equal(50);
|
||||
bitcore.Block.getBlockValue(1).div(c).toNumber().should.equal(50);
|
||||
bitcore.Block.getBlockValue(209999).div(c).toNumber().should.equal(50);
|
||||
bitcore.Block.getBlockValue(210000).div(c).toNumber().should.equal(25);
|
||||
bitcore.Block.getBlockValue(2100000).toNumber().should.equal(4882812);
|
||||
});
|
||||
|
||||
|
||||
it('#getStandardizedObject should return object', function() {
|
||||
var b = getBlock();
|
||||
var o = b.getStandardizedObject(b.txs);
|
||||
|
||||
o.hash.should.equal('000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11');
|
||||
o.n_tx.should.equal(22);
|
||||
o.size.should.equal(8003);
|
||||
var o2 = b.getStandardizedObject();
|
||||
o2.hash.should.equal('000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11');
|
||||
o2.size.should.equal(0);
|
||||
});
|
||||
|
||||
|
||||
it('#miner should call the callback', function(done) {
|
||||
var b = getBlock();
|
||||
var Miner = function() {};
|
||||
Miner.prototype.solve = function (header,target,cb) {
|
||||
this.called=1;
|
||||
should.exist(header);
|
||||
should.exist(target);
|
||||
return cb();
|
||||
};
|
||||
var miner = new Miner();
|
||||
b.solve(miner, function () {
|
||||
miner.called.should.equal(1);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('#createCoinbaseTx should create a tx', function() {
|
||||
var b = new Block();
|
||||
var pubkey = new Buffer('02d20b3fba521dcf88dfaf0eee8c15a8ba692d7eb0cb957d5bcf9f4cc052fb9cc6');
|
||||
var tx = b.createCoinbaseTx(pubkey);
|
||||
should.exist(tx);
|
||||
tx.isCoinBase().should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -30,3 +30,6 @@ module.exports.dataSigNonCanonical = dataSigNonCanonical;
|
|||
module.exports.dataBase58KeysValid = dataBase58KeysValid;
|
||||
module.exports.dataBase58KeysInvalid = dataBase58KeysInvalid;
|
||||
|
||||
var buffer = new Buffer(fs.readFileSync('test/data/blk86756-testnet.dat'));
|
||||
module.exports.dataRawBlock = buffer;
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ function MissingSourceError(msg, missingTxHash) {
|
|||
// TODO: Since this happens in normal operation, perhaps we should
|
||||
// avoid generating a whole stack trace.
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
// This is not compatible with firefox.
|
||||
// Error.captureStackTrace(this, arguments.callee);
|
||||
this.message = msg;
|
||||
this.missingTxHash = missingTxHash;
|
||||
this.name = 'MissingSourceError';
|
||||
|
@ -19,6 +20,7 @@ MissingSourceError.prototype.__proto__ = Error.prototype;
|
|||
|
||||
exports.MissingSourceError = MissingSourceError;
|
||||
|
||||
|
||||
/**
|
||||
* Used in several places to indicate invalid data.
|
||||
*
|
||||
|
@ -29,7 +31,9 @@ function VerificationError(msg, missingTxHash) {
|
|||
// TODO: Since this happens in normal operation, perhaps we should
|
||||
// avoid generating a whole stack trace.
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this, arguments.callee);
|
||||
|
||||
// This is not compatible with firefox.
|
||||
// Error.captureStackTrace(this, arguments.callee);
|
||||
this.message = msg;
|
||||
this.missingTxHash = missingTxHash;
|
||||
this.name = 'VerificationError';
|
||||
|
|
11
util/util.js
11
util/util.js
|
@ -359,8 +359,17 @@ var generateNonce = exports.generateNonce = function() {
|
|||
*/
|
||||
var decodeDiffBits = exports.decodeDiffBits = function(diffBits, asBigInt) {
|
||||
diffBits = +diffBits;
|
||||
|
||||
var target = bignum(diffBits & 0xffffff);
|
||||
target = target.shiftLeft(8 * ((diffBits >>> 24) - 3));
|
||||
/*
|
||||
* shiftLeft is not implemented on the bignum browser
|
||||
*
|
||||
* target = target.shiftLeft(8*((diffBits >>> 24) - 3));
|
||||
*/
|
||||
|
||||
var mov = 8*((diffBits >>> 24) - 3);
|
||||
while (mov-- > 0)
|
||||
target = target.mul(2);
|
||||
|
||||
if (asBigInt) {
|
||||
return target;
|
||||
|
|
Loading…
Reference in New Issue