Skip to content

Commit 8c6b991

Browse files
author
Patrick Nagurny
committed
add getBlockHashesByTimestamp
1 parent 13b5c06 commit 8c6b991

File tree

3 files changed

+127
-6
lines changed

3 files changed

+127
-6
lines changed

docs/services/db.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,13 @@ node.getBlock(blockHash, function(err, block) {
3232
//...
3333
});
3434
```
35+
36+
Get Block Hashes by Timestamp range
37+
38+
var time1 = 1441911000; // Notice time is in seconds not milliseconds
39+
var time2 = 1441914000;
40+
41+
node.getBlockHashesByTimestamp(time1, time2, function(err, hashes) {
42+
//...
43+
});
44+
```

lib/services/db.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ util.inherits(DB, Service);
6060

6161
DB.dependencies = ['bitcoind'];
6262

63+
DB.PREFIXES = {
64+
BLOCKS: 'blk'
65+
};
66+
6367
DB.prototype._setDataPath = function() {
6468
$.checkState(this.node.datadir, 'Node is expected to have a "datadir" property');
6569
var regtest = Networks.get('regtest');
@@ -177,6 +181,7 @@ DB.prototype.transactionHandler = function(txInfo) {
177181
DB.prototype.getAPIMethods = function() {
178182
var methods = [
179183
['getBlock', this, this.getBlock, 1],
184+
['getBlockHashesByTimestamp', this, this.getBlockHashesByTimestamp, 2],
180185
['getTransaction', this, this.getTransaction, 2],
181186
['getTransactionWithBlockInfo', this, this.getTransactionWithBlockInfo, 2],
182187
['sendTransaction', this, this.sendTransaction, 1],
@@ -194,6 +199,37 @@ DB.prototype.getBlock = function(hash, callback) {
194199
});
195200
};
196201

202+
DB.prototype.getBlockHashesByTimestamp = function(start, end, callback) {
203+
var hashes = [];
204+
205+
var stream = this.store.createReadStream({
206+
start: [DB.PREFIXES.BLOCKS, start].join('-'),
207+
end: [DB.PREFIXES.BLOCKS, end].join('-')
208+
});
209+
210+
stream.on('data', function(data) {
211+
hashes.push(data.value);
212+
});
213+
214+
var error;
215+
216+
stream.on('error', function(streamError) {
217+
if (streamError) {
218+
error = streamError;
219+
}
220+
});
221+
222+
stream.on('close', function() {
223+
if (error) {
224+
return callback(error);
225+
}
226+
227+
callback(null, hashes);
228+
});
229+
230+
return stream;
231+
};
232+
197233
DB.prototype.getTransaction = function(txid, queryMempool, callback) {
198234
this.node.services.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) {
199235
if (err) {
@@ -371,6 +407,13 @@ DB.prototype.runAllBlockHandlers = function(block, add, callback) {
371407
this.subscriptions.block[i].emit('block', block.hash);
372408
}
373409

410+
// Update block index
411+
operations.push({
412+
type: add ? 'put' : 'del',
413+
key: [DB.PREFIXES.BLOCKS, block.header.timestamp].join('-'),
414+
value: block.hash
415+
});
416+
374417
async.eachSeries(
375418
this.node.services,
376419
function(mod, next) {

test/services/db.unit.js

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,62 @@ describe('DB Service', function() {
369369
});
370370
});
371371

372+
describe('#getBlockHashesByTimestamp', function() {
373+
it('should get the correct block hashes', function(done) {
374+
var db = new DB(baseConfig);
375+
var readStream = new EventEmitter();
376+
db.store = {
377+
createReadStream: sinon.stub().returns(readStream)
378+
};
379+
380+
var block1 = {
381+
hash: '00000000050a6d07f583beba2d803296eb1e9d4980c4a20f206c584e89a4f02b',
382+
timestamp: 1441911909
383+
};
384+
385+
var block2 = {
386+
hash: '000000000383752a55a0b2891ce018fd0fdc0b6352502772b034ec282b4a1bf6',
387+
timestamp: 1441913112
388+
};
389+
390+
db.getBlockHashesByTimestamp(1441911000, 1441914000, function(err, hashes) {
391+
should.not.exist(err);
392+
hashes.should.deep.equal([block1.hash, block2.hash]);
393+
done();
394+
});
395+
396+
readStream.emit('data', {
397+
key: 'blk-' + block1.timestamp,
398+
value: block1.hash
399+
});
400+
401+
readStream.emit('data', {
402+
key: 'blk-' + block2.timestamp,
403+
value: block2.hash
404+
});
405+
406+
readStream.emit('close');
407+
});
408+
409+
it('should give an error if the stream has an error', function(done) {
410+
var db = new DB(baseConfig);
411+
var readStream = new EventEmitter();
412+
db.store = {
413+
createReadStream: sinon.stub().returns(readStream)
414+
};
415+
416+
db.getBlockHashesByTimestamp(1441911000, 1441914000, function(err, hashes) {
417+
should.exist(err);
418+
err.message.should.equal('error');
419+
done();
420+
});
421+
422+
readStream.emit('error', new Error('error'));
423+
424+
readStream.emit('close');
425+
});
426+
});
427+
372428
describe('#getPrevHash', function() {
373429
it('should return prevHash from bitcoind', function(done) {
374430
var db = new DB(baseConfig);
@@ -650,10 +706,22 @@ describe('DB Service', function() {
650706
batch: sinon.stub().callsArg(1)
651707
};
652708

709+
var block = {
710+
hash: '00000000000000000d0aaf93e464ddeb503655a0750f8b9c6eed0bdf0ccfc863',
711+
header: {
712+
timestamp: 1441906365
713+
}
714+
};
715+
653716
it('should call blockHandler in all services and perform operations', function(done) {
654-
db.runAllBlockHandlers('block', true, function(err) {
717+
db.runAllBlockHandlers(block, true, function(err) {
655718
should.not.exist(err);
656-
db.store.batch.args[0][0].should.deep.equal(['op1', 'op2', 'op3', 'op4', 'op5']);
719+
var blockOp = {
720+
type: 'put',
721+
key: 'blk-1441906365',
722+
value: '00000000000000000d0aaf93e464ddeb503655a0750f8b9c6eed0bdf0ccfc863'
723+
}
724+
db.store.batch.args[0][0].should.deep.equal([blockOp, 'op1', 'op2', 'op3', 'op4', 'op5']);
657725
done();
658726
});
659727
});
@@ -663,7 +731,7 @@ describe('DB Service', function() {
663731
Service3.prototype.blockHandler = sinon.stub().callsArgWith(2, new Error('error'));
664732
db.node.services.service3 = new Service3();
665733

666-
db.runAllBlockHandlers('block', true, function(err) {
734+
db.runAllBlockHandlers(block, true, function(err) {
667735
should.exist(err);
668736
done();
669737
});
@@ -675,7 +743,7 @@ describe('DB Service', function() {
675743
service3: new Service3()
676744
};
677745

678-
db.runAllBlockHandlers('block', true, function(err) {
746+
db.runAllBlockHandlers(block, true, function(err) {
679747
should.not.exist(err);
680748
done();
681749
});
@@ -688,7 +756,7 @@ describe('DB Service', function() {
688756
};
689757

690758
(function() {
691-
db.runAllBlockHandlers('block', true, function(err) {
759+
db.runAllBlockHandlers(block, true, function(err) {
692760
should.not.exist(err);
693761
});
694762
}).should.throw('bitcore.ErrorInvalidArgument');
@@ -701,7 +769,7 @@ describe('DB Service', function() {
701769
db.node = {};
702770
db.node.services = {};
703771
var methods = db.getAPIMethods();
704-
methods.length.should.equal(5);
772+
methods.length.should.equal(6);
705773
});
706774
});
707775

0 commit comments

Comments
 (0)