Merge pull request #50 from braydonf/prevhash
Use prevHash from bitcoind block index
This commit is contained in:
commit
078577499b
@ -4,22 +4,22 @@ var BitcoindJS = require('..');
|
|||||||
var BitcoinNode = BitcoindJS.Node;
|
var BitcoinNode = BitcoindJS.Node;
|
||||||
var chainlib = require('chainlib');
|
var chainlib = require('chainlib');
|
||||||
var log = chainlib.log;
|
var log = chainlib.log;
|
||||||
//log.debug = function() {};
|
log.debug = function() {};
|
||||||
|
|
||||||
var configuration = {
|
var configuration = {
|
||||||
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
|
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin'
|
||||||
network: 'testnet'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var node = new BitcoinNode(configuration);
|
var node = new BitcoinNode(configuration);
|
||||||
|
|
||||||
var startHeight;
|
var count = 0;
|
||||||
var count = 100;
|
var interval;
|
||||||
var times = new Array(count);
|
|
||||||
|
|
||||||
node.on('ready', function() {
|
node.on('ready', function() {
|
||||||
times[node.chain.tip.__height % count] = Date.now();
|
interval = setInterval(function() {
|
||||||
startHeight = node.chain.tip.__height;
|
log.info('Sync Status: Tip:', node.chain.tip.hash, 'Height:', node.chain.tip.__height, 'Rate:', count/10, 'blocks per second');
|
||||||
|
count = 0;
|
||||||
|
}, 10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
node.on('error', function(err) {
|
node.on('error', function(err) {
|
||||||
@ -27,13 +27,5 @@ node.on('error', function(err) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.chain.on('addblock', function(block) {
|
node.chain.on('addblock', function(block) {
|
||||||
console.log('New Best Tip:', block.hash);
|
count++;
|
||||||
var startTime = times[node.chain.tip.__height % count];
|
|
||||||
|
|
||||||
if(startTime) {
|
|
||||||
var timeElapsed = (Date.now() - startTime) / 1000;
|
|
||||||
console.log(Math.round(count / timeElapsed) + ' blocks per second');
|
|
||||||
}
|
|
||||||
|
|
||||||
times[node.chain.tip.__height % count] = Date.now();
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,6 +12,7 @@ if (process.env.BITCOINDJS_ENV !== 'test') {
|
|||||||
|
|
||||||
var chai = require('chai');
|
var chai = require('chai');
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
|
var BN = bitcore.crypto.BN;
|
||||||
var rimraf = require('rimraf');
|
var rimraf = require('rimraf');
|
||||||
var bitcoind;
|
var bitcoind;
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ var assert = chai.assert;
|
|||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var BitcoinRPC = require('bitcoind-rpc');
|
var BitcoinRPC = require('bitcoind-rpc');
|
||||||
var blockHashes = [];
|
var blockHashes = [];
|
||||||
var unspentTransactions = [];
|
var utxo;
|
||||||
var coinbasePrivateKey;
|
var coinbasePrivateKey;
|
||||||
var privateKey = bitcore.PrivateKey();
|
var privateKey = bitcore.PrivateKey();
|
||||||
var destKey = bitcore.PrivateKey();
|
var destKey = bitcore.PrivateKey();
|
||||||
@ -118,9 +119,22 @@ describe('Daemon Binding Functionality', function() {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tx = bitcore.Transaction();
|
var unspentTransaction = bitcore.Transaction();
|
||||||
tx.fromString(response.result.hex);
|
var outputIndex;
|
||||||
unspentTransactions.push(tx);
|
unspentTransaction.fromString(response.result.hex);
|
||||||
|
for (var i = 0; i < unspentTransaction.outputs.length; i++) {
|
||||||
|
var output = unspentTransaction.outputs[i];
|
||||||
|
if (output.script.toAddress(network).toString() === address.toString(network)) {
|
||||||
|
outputIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utxo = {
|
||||||
|
txid: unspentTransaction.hash,
|
||||||
|
outputIndex: outputIndex,
|
||||||
|
script: unspentTransaction.outputs[outputIndex].script,
|
||||||
|
satoshis: unspentTransaction.outputs[outputIndex].satoshis
|
||||||
|
};
|
||||||
|
|
||||||
// Include this transaction in a block so that it can
|
// Include this transaction in a block so that it can
|
||||||
// be spent in tests
|
// be spent in tests
|
||||||
@ -150,7 +164,7 @@ describe('Daemon Binding Functionality', function() {
|
|||||||
describe('mempool functionality', function() {
|
describe('mempool functionality', function() {
|
||||||
|
|
||||||
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
|
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
|
||||||
var utxo = {
|
var utxo1 = {
|
||||||
address: fromAddress,
|
address: fromAddress,
|
||||||
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
|
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
|
||||||
outputIndex: 0,
|
outputIndex: 0,
|
||||||
@ -160,14 +174,14 @@ describe('Daemon Binding Functionality', function() {
|
|||||||
var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
|
var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
|
||||||
var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up';
|
var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up';
|
||||||
var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf';
|
var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf';
|
||||||
var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY';
|
var privateKey1 = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY';
|
||||||
var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976';
|
var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976';
|
||||||
var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890';
|
var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890';
|
||||||
var tx = new bitcore.Transaction();
|
var tx = new bitcore.Transaction();
|
||||||
tx.from(utxo);
|
tx.from(utxo1);
|
||||||
tx.to(toAddress, 50000);
|
tx.to(toAddress, 50000);
|
||||||
tx.change(changeAddress);
|
tx.change(changeAddress);
|
||||||
tx.sign(privateKey);
|
tx.sign(privateKey1);
|
||||||
|
|
||||||
it('will add an unchecked transaction', function() {
|
it('will add an unchecked transaction', function() {
|
||||||
var added = bitcoind.addMempoolUncheckedTransaction(tx.serialize());
|
var added = bitcoind.addMempoolUncheckedTransaction(tx.serialize());
|
||||||
@ -233,19 +247,26 @@ describe('Daemon Binding Functionality', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('get block index', function() {
|
||||||
|
var expectedWork = new BN(6);
|
||||||
|
[1,2,3,4,5,6,7,8,9].forEach(function(i) {
|
||||||
|
it('generate block ' + i, function() {
|
||||||
|
var blockIndex = bitcoind.getBlockIndex(blockHashes[i]);
|
||||||
|
should.exist(blockIndex);
|
||||||
|
should.exist(blockIndex.chainWork);
|
||||||
|
var work = new BN(blockIndex.chainWork, 'hex');
|
||||||
|
work.cmp(expectedWork).should.equal(0);
|
||||||
|
expectedWork = expectedWork.add(new BN(2));
|
||||||
|
should.exist(blockIndex.prevHash);
|
||||||
|
blockIndex.prevHash.should.equal(blockHashes[i - 1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('send transaction functionality', function() {
|
describe('send transaction functionality', function() {
|
||||||
|
|
||||||
it('will not error and return the transaction hash', function() {
|
it('will not error and return the transaction hash', function() {
|
||||||
|
|
||||||
var unspentTx = unspentTransactions.shift();
|
|
||||||
|
|
||||||
var utxo = {
|
|
||||||
txid: unspentTx.hash,
|
|
||||||
outputIndex: 1,
|
|
||||||
script: unspentTx.outputs[1].script,
|
|
||||||
satoshis: unspentTx.outputs[1].satoshis
|
|
||||||
};
|
|
||||||
|
|
||||||
// create and sign the transaction
|
// create and sign the transaction
|
||||||
var tx = bitcore.Transaction();
|
var tx = bitcore.Transaction();
|
||||||
tx.from(utxo);
|
tx.from(utxo);
|
||||||
|
|||||||
@ -85,13 +85,14 @@ Chain.prototype.buildGenesisBlock = function buildGenesisBlock(options) {
|
|||||||
|
|
||||||
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
|
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var blockIndex = self.db.bitcoind.getBlockIndex(blockHash);
|
||||||
|
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
var weight = self.db.bitcoind.getChainWork(blockHash);
|
if (blockIndex) {
|
||||||
if(weight === undefined) {
|
callback(null, new BN(blockIndex.chainWork, 'hex'));
|
||||||
|
} else {
|
||||||
return callback(new Error('Weight not found for ' + blockHash));
|
return callback(new Error('Weight not found for ' + blockHash));
|
||||||
}
|
}
|
||||||
callback(null, new BN(weight, 'hex'));
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -340,8 +340,8 @@ Daemon.prototype.isSpent = function(txid, outputIndex) {
|
|||||||
return bitcoindjs.isSpent(txid, outputIndex);
|
return bitcoindjs.isSpent(txid, outputIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
Daemon.prototype.getChainWork = function(blockHash) {
|
Daemon.prototype.getBlockIndex = function(blockHash) {
|
||||||
return bitcoindjs.getChainWork(blockHash);
|
return bitcoindjs.getBlockIndex(blockHash);
|
||||||
};
|
};
|
||||||
|
|
||||||
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
|
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
|
||||||
|
|||||||
21
lib/db.js
21
lib/db.js
@ -46,10 +46,20 @@ DB.prototype.getBlock = function(hash, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DB.prototype.getPrevHash = function(blockHash, callback) {
|
||||||
|
var blockIndex = this.bitcoind.getBlockIndex(blockHash);
|
||||||
|
setImmediate(function() {
|
||||||
|
if (blockIndex) {
|
||||||
|
callback(null, blockIndex.prevHash);
|
||||||
|
} else {
|
||||||
|
callback(new Error('Could not get prevHash, block not found'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
DB.prototype.putBlock = function(block, callback) {
|
DB.prototype.putBlock = function(block, callback) {
|
||||||
// block is already stored in bitcoind, but we need to update
|
// block is already stored in bitcoind
|
||||||
// our prevhash index still
|
setImmediate(callback);
|
||||||
this._updatePrevHashIndex(block, callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DB.prototype.getTransaction = function(txid, queryMempool, callback) {
|
DB.prototype.getTransaction = function(txid, queryMempool, callback) {
|
||||||
@ -67,6 +77,11 @@ DB.prototype.validateBlockData = function(block, callback) {
|
|||||||
setImmediate(callback);
|
setImmediate(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DB.prototype._updatePrevHashIndex = function(block, callback) {
|
||||||
|
// bitcoind has the previous hash for each block
|
||||||
|
setImmediate(callback);
|
||||||
|
};
|
||||||
|
|
||||||
DB.prototype._updateWeight = function(hash, weight, callback) {
|
DB.prototype._updateWeight = function(hash, weight, callback) {
|
||||||
// bitcoind has all work for each block
|
// bitcoind has all work for each block
|
||||||
setImmediate(callback);
|
setImmediate(callback);
|
||||||
|
|||||||
@ -209,7 +209,7 @@ Node.prototype._loadConsensus = function(config) {
|
|||||||
var genesisBlock;
|
var genesisBlock;
|
||||||
if (config.genesis) {
|
if (config.genesis) {
|
||||||
genesisBlock = config.genesis;
|
genesisBlock = config.genesis;
|
||||||
} else if (config.testnet) {
|
} else if (config.network === 'testnet') {
|
||||||
genesisBlock = genesis.testnet;
|
genesisBlock = genesis.testnet;
|
||||||
} else {
|
} else {
|
||||||
genesisBlock = genesis.livenet;
|
genesisBlock = genesis.livenet;
|
||||||
|
|||||||
@ -980,12 +980,14 @@ NAN_METHOD(IsSpent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetChainWork()
|
* GetBlockIndex()
|
||||||
* bitcoindjs.getChainWork()
|
* bitcoindjs.getBlockIndex()
|
||||||
* Get the total amount of work (expected number of hashes) in the chain up to
|
* Get index information about a block by hash including:
|
||||||
* and including this block.
|
* - the total amount of work (expected number of hashes) in the chain up to
|
||||||
|
* and including this block.
|
||||||
|
* - the previous hash of the block
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(GetChainWork) {
|
NAN_METHOD(GetBlockIndex) {
|
||||||
Isolate* isolate = Isolate::GetCurrent();
|
Isolate* isolate = Isolate::GetCurrent();
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
@ -1000,7 +1002,15 @@ NAN_METHOD(GetChainWork) {
|
|||||||
} else {
|
} else {
|
||||||
blockIndex = mapBlockIndex[hash];
|
blockIndex = mapBlockIndex[hash];
|
||||||
arith_uint256 cw = blockIndex->nChainWork;
|
arith_uint256 cw = blockIndex->nChainWork;
|
||||||
NanReturnValue(Local<Value>::New(isolate, NanNew<String>(cw.GetHex())));
|
CBlockIndex* prevBlockIndex = blockIndex->pprev;
|
||||||
|
const uint256* prevHash = prevBlockIndex->phashBlock;
|
||||||
|
|
||||||
|
Local<Object> obj = NanNew<Object>();
|
||||||
|
|
||||||
|
obj->Set(NanNew<String>("chainWork"), NanNew<String>(cw.GetHex()));
|
||||||
|
obj->Set(NanNew<String>("prevHash"), NanNew<String>(prevHash->GetHex()));
|
||||||
|
|
||||||
|
NanReturnValue(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -1229,7 +1239,7 @@ init(Handle<Object> target) {
|
|||||||
NODE_SET_METHOD(target, "getTransaction", GetTransaction);
|
NODE_SET_METHOD(target, "getTransaction", GetTransaction);
|
||||||
NODE_SET_METHOD(target, "getInfo", GetInfo);
|
NODE_SET_METHOD(target, "getInfo", GetInfo);
|
||||||
NODE_SET_METHOD(target, "isSpent", IsSpent);
|
NODE_SET_METHOD(target, "isSpent", IsSpent);
|
||||||
NODE_SET_METHOD(target, "getChainWork", GetChainWork);
|
NODE_SET_METHOD(target, "getBlockIndex", GetBlockIndex);
|
||||||
NODE_SET_METHOD(target, "getMempoolOutputs", GetMempoolOutputs);
|
NODE_SET_METHOD(target, "getMempoolOutputs", GetMempoolOutputs);
|
||||||
NODE_SET_METHOD(target, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction);
|
NODE_SET_METHOD(target, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction);
|
||||||
NODE_SET_METHOD(target, "verifyScript", VerifyScript);
|
NODE_SET_METHOD(target, "verifyScript", VerifyScript);
|
||||||
|
|||||||
@ -23,7 +23,7 @@ NAN_METHOD(GetBlock);
|
|||||||
NAN_METHOD(GetTransaction);
|
NAN_METHOD(GetTransaction);
|
||||||
NAN_METHOD(GetInfo);
|
NAN_METHOD(GetInfo);
|
||||||
NAN_METHOD(IsSpent);
|
NAN_METHOD(IsSpent);
|
||||||
NAN_METHOD(GetChainWork);
|
NAN_METHOD(GetBlockIndex);
|
||||||
NAN_METHOD(GetMempoolOutputs);
|
NAN_METHOD(GetMempoolOutputs);
|
||||||
NAN_METHOD(AddMempoolUncheckedTransaction);
|
NAN_METHOD(AddMempoolUncheckedTransaction);
|
||||||
NAN_METHOD(VerifyScript);
|
NAN_METHOD(VerifyScript);
|
||||||
|
|||||||
@ -93,20 +93,22 @@ describe('Bitcoin Chain', function() {
|
|||||||
var chain = new Chain();
|
var chain = new Chain();
|
||||||
chain.db = {
|
chain.db = {
|
||||||
bitcoind: {
|
bitcoind: {
|
||||||
getChainWork: sinon.stub().returns(work)
|
getBlockIndex: sinon.stub().returns({
|
||||||
|
chainWork: work
|
||||||
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should give the weight as a BN', function(done) {
|
it('should give the weight as a BN', function(done) {
|
||||||
chain.getWeight('hash', function(err, weight) {
|
chain.getWeight('hash', function(err, weight) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
weight.toString(16).should.equal('5a7b3c42ea8b844374e9');
|
weight.toString(16, 64).should.equal(work);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should give an error if the weight is undefined', function(done) {
|
it('should give an error if the weight is undefined', function(done) {
|
||||||
chain.db.bitcoind.getChainWork = sinon.stub().returns(undefined);
|
chain.db.bitcoind.getBlockIndex = sinon.stub().returns(undefined);
|
||||||
chain.getWeight('hash2', function(err, weight) {
|
chain.getWeight('hash2', function(err, weight) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
done();
|
done();
|
||||||
|
|||||||
@ -42,12 +42,10 @@ describe('Bitcoin DB', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#putBlock', function() {
|
describe('#putBlock', function() {
|
||||||
it('should call _updatePrevHashIndex', function(done) {
|
it('should call callback', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db._updatePrevHashIndex = sinon.stub().callsArg(1);
|
|
||||||
db.putBlock('block', function(err) {
|
db.putBlock('block', function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
db._updatePrevHashIndex.called.should.equal(true);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -309,7 +309,7 @@ describe('Bitcoind Node', function() {
|
|||||||
});
|
});
|
||||||
it('should use the testnet genesis if testnet is specified', function() {
|
it('should use the testnet genesis if testnet is specified', function() {
|
||||||
var config = {
|
var config = {
|
||||||
testnet: true
|
network: 'testnet'
|
||||||
};
|
};
|
||||||
node._loadConsensus(config);
|
node._loadConsensus(config);
|
||||||
should.exist(node.chain);
|
should.exist(node.chain);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user