insight-api
Advanced tools
Comparing version 5.0.0-beta.14 to 5.0.0-beta.15
@@ -238,6 +238,8 @@ 'use strict'; | ||
self.transformAddressHistoryForMultiTxs(result.items, transformOptions, function(err, items) { | ||
if (err) { | ||
return self.common.handleErrors(err, res); | ||
} | ||
res.jsonp({ | ||
var ret = { | ||
totalItems: result.totalCount, | ||
@@ -247,3 +249,5 @@ from: options.from, | ||
items: items | ||
}); | ||
}; | ||
res.jsonp(ret); | ||
}); | ||
@@ -250,0 +254,0 @@ |
@@ -9,3 +9,2 @@ 'use strict'; | ||
var pools = require('../pools.json'); | ||
var BN = bitcore.crypto.BN; | ||
var LRU = require('lru-cache'); | ||
@@ -114,2 +113,5 @@ var Common = require('./common'); | ||
} | ||
if (!blockBuffer) { | ||
return next(); | ||
} | ||
req.rawBlock = { | ||
@@ -152,5 +154,5 @@ rawblock: blockBuffer.toString('hex') | ||
previousblockhash: info.prevHash, | ||
nextblockhash: null, | ||
reward: null, | ||
isMainChain: true, | ||
nextblockhash: info.nextHash, | ||
reward: this.getBlockReward(block.txs[0]), | ||
isMainChain: block.isMainChain, | ||
poolInfo: this.getPoolInfo(block.txs[0]) | ||
@@ -209,2 +211,6 @@ }; | ||
if (!blockBuffer) { | ||
return next(); | ||
} | ||
var block = bcoin.block.fromRaw(blockBuffer, 'hex'); | ||
@@ -221,4 +227,4 @@ | ||
height: header.height, | ||
size: block.size, | ||
virtualSize: block.virtualSize, | ||
size: block.getSize(), | ||
virtualSize: block.getVirtualSize(), | ||
hash: hash, | ||
@@ -323,2 +329,10 @@ time: header.timestamp, | ||
BlockController.prototype.getBlockReward = function(tx) { | ||
var amt = 0; | ||
tx.outputs.forEach(function(output) { | ||
amt += output.value; | ||
}); | ||
return bitcore.Unit.fromSatoshis(amt).toBTC(); | ||
}; | ||
BlockController.prototype.getPoolInfo = function(tx) { | ||
@@ -348,16 +362,2 @@ if (!tx) { | ||
BlockController.prototype.getBlockReward = function(height) { | ||
var halvings = Math.floor(height / 210000); | ||
// Force block reward to zero when right shift is undefined. | ||
if (halvings >= 64) { | ||
return 0; | ||
} | ||
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. | ||
var subsidy = new BN(50 * 1e8); | ||
subsidy = subsidy.shrn(halvings); | ||
return parseInt(subsidy.toString(10)); | ||
}; | ||
module.exports = BlockController; |
@@ -17,2 +17,3 @@ 'use strict'; | ||
this._address = this.node.services.address; | ||
this._p2p = this.node.services.p2p; | ||
this._network = this.node.network; | ||
@@ -100,3 +101,3 @@ if (this.node.network === 'livenet') { | ||
transformed.blockhash = transaction.__blockhash; | ||
transformed.blockhash = transaction.blockhash; | ||
transformed.blockheight = transaction.__height; | ||
@@ -145,5 +146,5 @@ transformed.confirmations = confirmations; | ||
transformed.doubleSpentTxID = null; // TODO | ||
//transformed.isConfirmed = null; // TODO | ||
//transformed.confirmations = null; // TODO | ||
//transformed.unconfirmedInput = null; // TODO | ||
transformed.isConfirmed = null; // TODO | ||
transformed.confirmations = null; // TODO | ||
transformed.unconfirmedInput = null; // TODO | ||
@@ -166,8 +167,7 @@ return transformed; | ||
//if (!options.noSpent) { | ||
// These aren't implemented in the new api | ||
//transformed.spentTxId = output.spentTxId || null; // we aren't tracking this with the bcoin implementation | ||
//transformed.spentIndex = _.isUndefined(output.spentIndex) ? null : output.spentIndex; | ||
//transformed.spentHeight = output.spentHeight || null; | ||
//} | ||
if (!options.noSpent) { | ||
transformed.spentTxId = output.spentTxId || null; // TODO | ||
transformed.spentIndex = _.isUndefined(output.spentIndex) ? null : output.spentIndex; // TODO | ||
transformed.spentHeight = output.spentHeight || null; // TODO | ||
} | ||
@@ -331,3 +331,3 @@ var address = output.getAddress(); | ||
var self = this; | ||
this._transaction.sendTransaction(req.body.rawtx, function(err, txid) { | ||
this._p2p.sendTransaction(req.body.rawtx, function(err, txid) { | ||
if(err) { | ||
@@ -334,0 +334,0 @@ // TODO handle specific errors |
{ | ||
"name": "insight-api", | ||
"description": "A Bitcoin blockchain REST and web socket API service for Bitcore Node.", | ||
"version": "5.0.0-beta.14", | ||
"version": "5.0.0-beta.15", | ||
"repository": "git://github.com/bitpay/insight-api.git", | ||
@@ -6,0 +6,0 @@ "bugs": { |
@@ -551,5 +551,5 @@ 'use strict'; | ||
//console.log(data); | ||
expect(data.items.length).to.equal(3); | ||
expect(data.items.length).to.equal(2); | ||
expect(data.from).to.equal(0); | ||
expect(data.to).to.equal(3); | ||
expect(data.to).to.equal(2); | ||
done(); | ||
@@ -585,5 +585,5 @@ | ||
//console.log(data); | ||
expect(data.items.length).to.equal(3); | ||
expect(data.items.length).to.equal(2); | ||
expect(data.from).to.equal(0); | ||
expect(data.to).to.equal(3); | ||
expect(data.to).to.equal(2); | ||
done(); | ||
@@ -590,0 +590,0 @@ |
@@ -5,9 +5,9 @@ 'use strict'; | ||
Reorg states (enumerated): | ||
Reorg states (enumerated): | ||
1. block service fully sync'ed, p2p block subscription active (normal operating mode) | ||
2. block service not sync'ed, reorg common ancestor height greater than current block service tip height (reorg while sync, not affected) | ||
3. block service not sync'ed, reorg common ancestor height less than current block service tip height (reorg while sync, affected) | ||
4. system shutdown, reorg wipes out header and block tip (reorg while shutdown, affected) | ||
5. system shutdown, reorg common ancestor height greater than the current header tip (reorg while shutdown, not affected) | ||
1. block service fully sync'ed, p2p block subscription active (normal operating mode) | ||
2. block service not sync'ed, reorg common ancestor height greater than current block service tip height (reorg while sync, not affected) | ||
3. block service not sync'ed, reorg common ancestor height less than current block service tip height (reorg while sync, affected) | ||
4. system shutdown, reorg wipes out header and block tip (reorg while shutdown, affected) | ||
5. reorg from a block that was mined from an already-orphaned block | ||
@@ -35,3 +35,2 @@ */ | ||
var BcoinTx = bcoin.tx; | ||
var _ = require('lodash'); | ||
@@ -50,6 +49,2 @@ var tx = BcoinTx.fromRaw('0200000001d7cf6999aa1eeee5bf954071d974bff51aa7126494a071ec0ba7820d98fc3106010000006a473044022072a784b07c68abde667a27587eb3979ee1f3ca5dc78e665801150492268c1307022054fdd4aafdcb15fc4cb7555c3a38a9ade8bb8af57c95be974b06ed16a713355d012103d3b1e94531d8b7ed3eb54751abe79786c1aa9adc1b5bc35cfced49693095b68dfeffffff0245519103000000001976a914beac8701ec4a6970ed239a47671c967b50da43d588ac80969800000000001976a914c98d54f2eb6c8970d50f7e90c9b3f4b71af9493088ac00000000', 'hex'); | ||
this.hasNullItems = function() { | ||
return array.length !== _.compact(array).length; | ||
}; | ||
this.remove = function(item) { | ||
@@ -97,8 +92,17 @@ var index = object[item]; | ||
var getOrphanedBlock = function() { | ||
return BcoinBlock.fromRaw(require('./data/blocks_orphaned.json')[0], 'hex'); | ||
}; | ||
var TestBitcoind = function TestBitcoind() { | ||
var self = this; | ||
self.blocks = []; | ||
self.currentBlockIndex = 0; | ||
self._orphans = {}; | ||
self.reorientData = function(block) { | ||
var lastHash = self.blocks.getLastIndex().rhash(); | ||
self.blocks.remove(lastHash); | ||
self.blocks.set(block.rhash(), block); | ||
}; | ||
self._getHeaders = function() { | ||
@@ -171,3 +175,7 @@ var ret = []; | ||
} | ||
msg.push(messages.Block(self.blocks.get(hash), { Block: BcoinBlock })); | ||
var block = self.blocks.get(hash); | ||
if (!block) { | ||
block = self._orphans[hash]; | ||
} | ||
msg.push(messages.Block(block, { Block: BcoinBlock })); | ||
} | ||
@@ -187,6 +195,10 @@ | ||
// of the resource. | ||
self.sendBlock = function(block) { | ||
var lastHash = self.blocks.getLastIndex().rhash(); | ||
self.blocks.remove(lastHash); | ||
self.blocks.set(block.rhash(), block); | ||
self.sendBlock = function(block, doNotChangeHeaders) { | ||
if (!doNotChangeHeaders) { | ||
var lastHash = self.blocks.getLastIndex().rhash(); | ||
self.blocks.remove(lastHash); | ||
self.blocks.set(block.rhash(), block); | ||
} else { | ||
self._orphans[block.rhash()] = block; | ||
} | ||
var inv = p2p.Inventory.forBlock(block.rhash()); | ||
@@ -720,3 +732,3 @@ var message = messages.Inventory([inv]); | ||
/* | ||
3. block service not sync'ed, reorg common ancestor height less than current block service tip heigh (reorg while sync, affected) | ||
3. block service not sync'ed, reorg common ancestor height less than current block service tip heigh (reorg while sync, affected) | ||
*/ | ||
@@ -773,11 +785,99 @@ var performTest3 = function(fakeServer, callback) { | ||
/* | ||
4. system shutdown, reorg wipes out header and block tip (reorg while shutdown, affected) | ||
4. system shutdown, reorg wipes out header and block tip (reorg while shutdown, affected) | ||
*/ | ||
var performTest4 = function() { | ||
var performTest4 = function(fakeServer, callback) { | ||
async.series([ | ||
// 0. reset the test directories | ||
function(next) { | ||
console.log('step 0: setting up directories.'); | ||
var dirs = bitcoinDataDirs.concat([bitcoreDataDir]); | ||
resetDirs(dirs, function(err) { | ||
if (err) { | ||
return next(err); | ||
} | ||
writeBitcoreConf(); | ||
next(); | ||
}); | ||
}, | ||
// 1. start fake server | ||
function(next) { | ||
console.log('step 1: starting fake server.'); | ||
fakeServer.start(); | ||
next(); | ||
}, | ||
// 2. start bitcore | ||
function(next) { | ||
console.log('step 2: start bitcore and let sync.'); | ||
blocksGenerated = 7; | ||
startBitcore(next); | ||
}, | ||
// 3. shutdown bitcore | ||
function(next) { | ||
console.log('step 3: shut down bitcore.'); | ||
shutdownBitcore(next); | ||
}, | ||
// 4. setup the fake server to send a reorg'ed set of headers | ||
function(next) { | ||
console.log('step 4: setup fake server to send reorg set of headers.'); | ||
var reorgBlock = getReorgBlock(); | ||
fakeServer.reorientData(reorgBlock); | ||
next(); | ||
}, | ||
// 5. start up bitcore once again | ||
function(next) { | ||
console.log('step 5: start up bitcore.'); | ||
blocksGenerated = 7; | ||
startBitcore(next); | ||
} | ||
], function(err) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
callback(); | ||
}); | ||
}; | ||
/* | ||
5. system shutdown, reorg common ancestor height greater than the current header tip (reorg while shutdown, not affected) | ||
5. reorg from a block that was mined from an already-orphaned block | ||
*/ | ||
var performTest5 = function() { | ||
var performTest5 = function(fakeServer, callback) { | ||
async.series([ | ||
// 0. reset the test directories | ||
function(next) { | ||
console.log('step 0: setting up directories.'); | ||
var dirs = bitcoinDataDirs.concat([bitcoreDataDir]); | ||
resetDirs(dirs, function(err) { | ||
if (err) { | ||
return next(err); | ||
} | ||
writeBitcoreConf(); | ||
next(); | ||
}); | ||
}, | ||
// 1. start fake server | ||
function(next) { | ||
console.log('step 1: starting fake server.'); | ||
fakeServer.start(); | ||
next(); | ||
}, | ||
// 2. start bitcore | ||
function(next) { | ||
console.log('step 2: start bitcore and let sync.'); | ||
blocksGenerated = 7; | ||
startBitcore(next); | ||
}, | ||
// 3. send in a block that has nothing to do with anything in my chain. | ||
function(next) { | ||
console.log('step 3: send in an orphaned block.'); | ||
var orphanedBlock = getOrphanedBlock(); | ||
fakeServer.sendBlock(orphanedBlock, true); | ||
next(); | ||
} | ||
], function(err) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
callback(); | ||
}); | ||
}; | ||
@@ -800,18 +900,18 @@ | ||
/* | ||
What this test does: | ||
What this test does: | ||
step 0: set up directories | ||
step 1: start 2 bitcoinds. | ||
step 2: check to see if bitcoind's are connected to each other. | ||
step 3: generate 10 blocks on bitcoin 1. | ||
step 4: check for synced blocks between bitcoinds. | ||
step 5: start bitcore | ||
step 6: shut down all bitcoind's. | ||
step 7: change config of bitcoin 2 and restart it. | ||
step 8: generate 100 blocks on bitcoin 2. | ||
step 9: sync 100 blocks to bitcore. | ||
step 10: shut down bitcoin 2. | ||
step 11: start up bitcoin 1 | ||
step 12: generate 1 block | ||
step 13: Wait for bitcore to reorg to block height 11. | ||
step 0: set up directories | ||
step 1: start 2 bitcoinds. | ||
step 2: check to see if bitcoind's are connected to each other. | ||
step 3: generate 10 blocks on bitcoin 1. | ||
step 4: check for synced blocks between bitcoinds. | ||
step 5: start bitcore | ||
step 6: shut down all bitcoind's. | ||
step 7: change config of bitcoin 2 and restart it. | ||
step 8: generate 100 blocks on bitcoin 2. | ||
step 9: sync 100 blocks to bitcore. | ||
step 10: shut down bitcoin 2. | ||
step 11: start up bitcoin 1 | ||
step 12: generate 1 block | ||
step 13: Wait for bitcore to reorg to block height 11. | ||
*/ | ||
@@ -855,122 +955,207 @@ | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
}); | ||
it('should reorg correctly when the block service is initially syncing, but it has not sync\'ed to the point where the reorg has happened.', function(done) { | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
done(); | ||
}); | ||
}); | ||
/* | ||
What this test does: | ||
it('should reorg correctly when the block service is initially syncing, but it has not sync\'ed to the point where the reorg has happened.', function(done) { | ||
step 0: setup directories | ||
step 1: start fake server (fake bitcoin) | ||
step 2: init server with blocks (the initial set from which bitcore will sync) | ||
step 3: start bitcore in slow mode (slow the block service's sync speed down so we | ||
can send a reorg block to the header service while the block service is still syncing. | ||
step 4: send an inventory message with a reorg block hash | ||
/* | ||
What this test does: | ||
the header service will get this message, discover the reorg, handle the reorg | ||
and call onHeaders on the block service, query bitcore for the results | ||
*/ | ||
performTest2(fakeServer, function(err) { | ||
step 0: setup directories | ||
step 1: start fake server (fake bitcoin) | ||
step 2: init server with blocks (the initial set from which bitcore will sync) | ||
step 3: start bitcore in slow mode (slow the block service's sync speed down so we | ||
can send a reorg block to the header service while the block service is still syncing. | ||
step 4: send an inventory message with a reorg block hash | ||
if(err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + getReorgBlock().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
the header service will get this message, discover the reorg, handle the reorg | ||
and call onHeaders on the block service, query bitcore for the results | ||
*/ | ||
performTest2(fakeServer, function(err) { | ||
request(httpOpts, function(err, data) { | ||
if(err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + getReorgBlock().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
if(err) { | ||
return done(err); | ||
} | ||
request(httpOpts, function(err, data) { | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
if(err) { | ||
return done(err); | ||
} | ||
}); | ||
}, 2000); | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
}); | ||
}, 2000); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('Reorg case 3: block service not sync\'ed, reorg common ancestor height less than ' + | ||
'current block service tip height (reorg while sync, not affected)', function() { | ||
'current block service tip height (reorg while sync, not affected)', function() { | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
done(); | ||
}); | ||
}); | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
done(); | ||
}); | ||
}); | ||
it('should reorg correctly when the block service is initially syncing and the block service has received at least the common header.', function(done) { | ||
it('should reorg correctly when the block service is initially syncing and the block service has received at least the common header.', function(done) { | ||
/* | ||
What this test does: | ||
/* | ||
What this test does: | ||
step 0: setup directories | ||
step 1: start fake server (fake bitcoin) | ||
step 2: init server with blocks (the initial set from which bitcore will sync) | ||
step 3: start bitcore in slow mode | ||
step 4: send an inventory message with a reorg block hash | ||
step 0: setup directories | ||
step 1: start fake server (fake bitcoin) | ||
step 2: init server with blocks (the initial set from which bitcore will sync) | ||
step 3: start bitcore in slow mode | ||
step 4: send an inventory message with a reorg block hash | ||
*/ | ||
performTest3(fakeServer, function(err) { | ||
*/ | ||
performTest3(fakeServer, function(err) { | ||
if(err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + getReorgBlock().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
request(httpOpts, function(err, data) { | ||
if(err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + getReorgBlock().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
request(httpOpts, function(err, data) { | ||
}); | ||
}, 2000); | ||
if(err) { | ||
return done(err); | ||
} | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
}); | ||
}, 2000); | ||
}); | ||
}); | ||
}); | ||
describe('Case 4: system shutdown, reorg wipes out header and block tip (reorg while shutdown, affected)', function() { | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
done(); | ||
}); | ||
}); | ||
it('should reorg when, while the node is shut down, our header tip is reorged out of existence.', function(done) { | ||
performTest4(fakeServer, function(err) { | ||
if (err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + getReorgBlock().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
request(httpOpts, function(err, data) { | ||
if(err) { | ||
return done(err); | ||
} | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
}); | ||
}, 2000); | ||
}); | ||
}); | ||
}); | ||
describe('Case 5: reorg from a block that was mined from an already-orphaned block', function() { | ||
var fakeServer; | ||
before(function(done) { | ||
fakeServer = new TestBitcoind(); | ||
done(); | ||
}); | ||
after(function(done) { | ||
shutdownBitcore(function() { | ||
fakeServer.stop(); | ||
done(); | ||
}); | ||
}); | ||
it('should launch a reorg, yet no mainchain blocks will be affected when a new block comes in that is not mainchain to begin with', function(done) { | ||
performTest5(fakeServer, function(err) { | ||
if (err) { | ||
return done(err); | ||
} | ||
setTimeout(function() { | ||
var httpOpts = { | ||
hostname: 'localhost', | ||
port: 53001, | ||
path: 'http://localhost:53001/api/block/' + fakeServer.blocks.getLastIndex().rhash(), | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}; | ||
request(httpOpts, function(err, data) { | ||
if(err) { | ||
return done(err); | ||
} | ||
console.log(data); | ||
expect(data.height).to.equal(7); | ||
done(); | ||
}); | ||
}, 2000); | ||
}); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
728545
36
8785