Merge pull request #50 from braydonf/prevhash

Use prevHash from bitcoind block index
This commit is contained in:
Patrick Nagurny 2015-07-23 08:17:12 -06:00
commit 078577499b
11 changed files with 97 additions and 58 deletions

View File

@ -4,22 +4,22 @@ var BitcoindJS = require('..');
var BitcoinNode = BitcoindJS.Node;
var chainlib = require('chainlib');
var log = chainlib.log;
//log.debug = function() {};
log.debug = function() {};
var configuration = {
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin',
network: 'testnet'
datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin'
};
var node = new BitcoinNode(configuration);
var startHeight;
var count = 100;
var times = new Array(count);
var count = 0;
var interval;
node.on('ready', function() {
times[node.chain.tip.__height % count] = Date.now();
startHeight = node.chain.tip.__height;
interval = setInterval(function() {
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) {
@ -27,13 +27,5 @@ node.on('error', function(err) {
});
node.chain.on('addblock', function(block) {
console.log('New Best Tip:', block.hash);
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();
count++;
});

View File

@ -12,6 +12,7 @@ if (process.env.BITCOINDJS_ENV !== 'test') {
var chai = require('chai');
var bitcore = require('bitcore');
var BN = bitcore.crypto.BN;
var rimraf = require('rimraf');
var bitcoind;
@ -21,7 +22,7 @@ var assert = chai.assert;
var sinon = require('sinon');
var BitcoinRPC = require('bitcoind-rpc');
var blockHashes = [];
var unspentTransactions = [];
var utxo;
var coinbasePrivateKey;
var privateKey = bitcore.PrivateKey();
var destKey = bitcore.PrivateKey();
@ -118,9 +119,22 @@ describe('Daemon Binding Functionality', function() {
throw err;
}
var tx = bitcore.Transaction();
tx.fromString(response.result.hex);
unspentTransactions.push(tx);
var unspentTransaction = bitcore.Transaction();
var outputIndex;
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
// be spent in tests
@ -150,7 +164,7 @@ describe('Daemon Binding Functionality', function() {
describe('mempool functionality', function() {
var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1';
var utxo = {
var utxo1 = {
address: fromAddress,
txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
outputIndex: 0,
@ -160,14 +174,14 @@ describe('Daemon Binding Functionality', function() {
var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc';
var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up';
var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf';
var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY';
var privateKey1 = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY';
var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976';
var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890';
var tx = new bitcore.Transaction();
tx.from(utxo);
tx.from(utxo1);
tx.to(toAddress, 50000);
tx.change(changeAddress);
tx.sign(privateKey);
tx.sign(privateKey1);
it('will add an unchecked transaction', function() {
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() {
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
var tx = bitcore.Transaction();
tx.from(utxo);

View File

@ -85,13 +85,14 @@ Chain.prototype.buildGenesisBlock = function buildGenesisBlock(options) {
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
var self = this;
var blockIndex = self.db.bitcoind.getBlockIndex(blockHash);
setImmediate(function() {
var weight = self.db.bitcoind.getChainWork(blockHash);
if(weight === undefined) {
if (blockIndex) {
callback(null, new BN(blockIndex.chainWork, 'hex'));
} else {
return callback(new Error('Weight not found for ' + blockHash));
}
callback(null, new BN(weight, 'hex'));
});
};

View File

@ -340,8 +340,8 @@ Daemon.prototype.isSpent = function(txid, outputIndex) {
return bitcoindjs.isSpent(txid, outputIndex);
};
Daemon.prototype.getChainWork = function(blockHash) {
return bitcoindjs.getChainWork(blockHash);
Daemon.prototype.getBlockIndex = function(blockHash) {
return bitcoindjs.getBlockIndex(blockHash);
};
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {

View File

@ -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) {
// block is already stored in bitcoind, but we need to update
// our prevhash index still
this._updatePrevHashIndex(block, callback);
// block is already stored in bitcoind
setImmediate(callback);
};
DB.prototype.getTransaction = function(txid, queryMempool, callback) {
@ -67,6 +77,11 @@ DB.prototype.validateBlockData = function(block, 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) {
// bitcoind has all work for each block
setImmediate(callback);

View File

@ -209,7 +209,7 @@ Node.prototype._loadConsensus = function(config) {
var genesisBlock;
if (config.genesis) {
genesisBlock = config.genesis;
} else if (config.testnet) {
} else if (config.network === 'testnet') {
genesisBlock = genesis.testnet;
} else {
genesisBlock = genesis.livenet;

View File

@ -980,12 +980,14 @@ NAN_METHOD(IsSpent) {
};
/**
* GetChainWork()
* bitcoindjs.getChainWork()
* Get the total amount of work (expected number of hashes) in the chain up to
* and including this block.
* GetBlockIndex()
* bitcoindjs.getBlockIndex()
* Get index information about a block by hash including:
* - 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();
HandleScope scope(isolate);
@ -1000,7 +1002,15 @@ NAN_METHOD(GetChainWork) {
} else {
blockIndex = mapBlockIndex[hash];
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, "getInfo", GetInfo);
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, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction);
NODE_SET_METHOD(target, "verifyScript", VerifyScript);

View File

@ -23,7 +23,7 @@ NAN_METHOD(GetBlock);
NAN_METHOD(GetTransaction);
NAN_METHOD(GetInfo);
NAN_METHOD(IsSpent);
NAN_METHOD(GetChainWork);
NAN_METHOD(GetBlockIndex);
NAN_METHOD(GetMempoolOutputs);
NAN_METHOD(AddMempoolUncheckedTransaction);
NAN_METHOD(VerifyScript);

View File

@ -93,20 +93,22 @@ describe('Bitcoin Chain', function() {
var chain = new Chain();
chain.db = {
bitcoind: {
getChainWork: sinon.stub().returns(work)
getBlockIndex: sinon.stub().returns({
chainWork: work
})
}
};
it('should give the weight as a BN', function(done) {
chain.getWeight('hash', function(err, weight) {
should.not.exist(err);
weight.toString(16).should.equal('5a7b3c42ea8b844374e9');
weight.toString(16, 64).should.equal(work);
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) {
should.exist(err);
done();

View File

@ -42,12 +42,10 @@ describe('Bitcoin DB', function() {
});
describe('#putBlock', function() {
it('should call _updatePrevHashIndex', function(done) {
it('should call callback', function(done) {
var db = new DB({store: memdown});
db._updatePrevHashIndex = sinon.stub().callsArg(1);
db.putBlock('block', function(err) {
should.not.exist(err);
db._updatePrevHashIndex.called.should.equal(true);
done();
});
});

View File

@ -309,7 +309,7 @@ describe('Bitcoind Node', function() {
});
it('should use the testnet genesis if testnet is specified', function() {
var config = {
testnet: true
network: 'testnet'
};
node._loadConsensus(config);
should.exist(node.chain);