diff --git a/api/controllers/blocks.js b/api/controllers/blocks.js new file mode 100644 index 00000000..97c6bbb7 --- /dev/null +++ b/api/controllers/blocks.js @@ -0,0 +1,102 @@ +'use strict'; + +var bitcore = require('bitcore'); +var _ = bitcore.deps._; +var $ = bitcore.util.preconditions; +var Block = bitcore.Block; + +var BitcoreNode = require('../../'); + +var Blocks = {}; + +var node; +Blocks.setNode = function(aNode) { + node = aNode; +}; + + +/* + * params + */ + +/* + * Finds a block by its hash + */ +Blocks.blockHashParam = function(req, res, next, blockHash) { + node.getBlock(blockHash) + .then(function(block) { + req.block = block; + }) + .then(next) + .catch(BitcoreNode.errors.Blocks.NotFound, function() { + res.status(404).send('Block with id ' + blockHash + ' not found'); + }); +}; + +/* + * Finds a block by its height + */ +Blocks.heightParam = function(req, res, next, height) { + height = parseInt(height); + node.getBlock(height) + .then(function(block) { + req.block = block; + }) + .then(next) + .catch(BitcoreNode.errors.Blocks.NotFound, function() { + res.status(404).send('Block with height ' + height + ' not found'); + }); +}; + + +/* + * controllers + */ + +/* + * Returns a list of blocks given certain query options. + * + * from: block height as lower limit (default: 0) + * to: ditto, but for the upper limit, non inclusive (default: 1000000) + * page: for paginating results (default: 0) + * offset: skip the first offset blocks (default: 0) + * limit: max amount of blocks returned (default: 10) + * + */ +Blocks.list = function(req, res) { + var from = parseInt(req.query.from || 0); + var to = parseInt(req.query.to || 1e6); + var offset = parseInt(req.query.offset || 0); + var limit = parseInt(req.query.limit || 10); + + if (to < from) { + res.status(422); + res.send('/v1/blocks/ "to" must be >= to "from"'); + return; + } + + node.listBlocks(from, to, offset, limit) + .then(function(blocks) { + res.send(blocks); + }); +}; + +Blocks.getLatest = function(req, res) { + node.getLatestBlock() + .then(function(block) { + req.block = block; + Blocks.get(req, res); + }); +}; + +Blocks.get = function(req, res) { + $.checkState(req.block instanceof Block); + res.send(req.block.toObject()); +}; + +Blocks.getBlockError = function(req, res) { + res.status(422); + res.send('/v1/blocks/ parameter must be a 64 digit hex or block height integer'); +}; + +module.exports = Blocks; diff --git a/api/controllers/node.js b/api/controllers/node.js new file mode 100644 index 00000000..cc0835c2 --- /dev/null +++ b/api/controllers/node.js @@ -0,0 +1,16 @@ +'use strict'; + +var NodeStatus = {}; +var node; +NodeStatus.setNode = function(aNode) { + node = aNode; +}; + +NodeStatus.getStatus = function(req, res) { + node.getStatus() + .then(function(status) { + res.send(status); + }); +}; + +module.exports = NodeStatus; diff --git a/api/controllers/transactions.js b/api/controllers/transactions.js new file mode 100644 index 00000000..2cfdf35c --- /dev/null +++ b/api/controllers/transactions.js @@ -0,0 +1,88 @@ +'use strict'; + +var Promise = require('bluebird'); + +var bitcore = require('bitcore'); +var _ = bitcore.deps._; +var $ = bitcore.util.preconditions; +var Transaction = bitcore.Transaction; + +var BitcoreNode = require('../../'); + +var Transactions = {}; + +var node; +Transactions.setNode = function(aNode) { + node = aNode; +}; + + +/* + * params + */ + +/* + * Finds a transaction by its hash + */ +Transactions.txHashParam = function(req, res, next, txHash) { + node.getTransaction(txHash) + .then(function(tx) { + req.tx = tx; + }) + .then(next) + .catch(BitcoreNode.errors.Transactions.NotFound, function() { + res.status(404).send('Transaction with id ' + txHash + ' not found'); + }); +}; + + +/* + * controllers + */ + +/* + * get transaction by its hash + */ +Transactions.get = function(req, res) { + $.checkState(req.tx instanceof Transaction); + res.send(req.tx.toObject()); +}; + + +/** + * send a transaction to the bitcoin network + */ +Transactions.send = function(req, res) { + var raw = req.body.raw; + if (_.isUndefined(raw)) { + Transaction._sendError(res); + return; + } + var tx; + try { + tx = new Transaction(raw); + } catch (e) { + Transaction._sendError(res); + return; + } + node.broadcast(tx) + .then(function() { + res.send('Transaction broadcasted successfully'); + }) + .catch(BitcoreNode.errors.Transactions.CantBroadcast, function(err) { + res.status(422).send(err.message); + }); +}; + +Transaction._sendError = function(res) { + res.status(422); + res.send('/v1/transactions/send parameter must be a raw transaction hex'); +}; + + +Transactions.getTxError = function(req, res) { + res.status(422); + res.send('/v1/transactions/ parameter must be a 64 digit hex'); +}; + +module.exports = Transactions; diff --git a/api/index.js b/api/index.js index d11977c6..d0a21153 100755 --- a/api/index.js +++ b/api/index.js @@ -1,8 +1,11 @@ 'use strict'; -var config = require('config'); var BitcoreHTTP = require('./lib/http'); -var http = BitcoreHTTP.create(config.get('BitcoreHTTP')); -http.start(); +if (require.main === module) { + var config = require('config'); + var http = BitcoreHTTP.create(config.get('BitcoreHTTP')); + http.start(); +} +module.exports = BitcoreHTTP; diff --git a/api/routes/v1.js b/api/routes/v1.js index dec035bb..12d0ddf0 100644 --- a/api/routes/v1.js +++ b/api/routes/v1.js @@ -1,31 +1,42 @@ 'use strict'; var express = require('express'); +var NodeStatus = require('../controllers/node'); +var Blocks = require('../controllers/blocks'); +var Transactions = require('../controllers/transactions'); + function initRouter(node) { var router = express.Router(); + [NodeStatus, Blocks, Transactions].forEach(function(controller) { + controller.setNode(node); + }); + function mockResponse(req, res) { - res.send({'message': 'This is a mocked response'}); + res.send({ + 'message': 'This is a mocked response' + }); } + // parameter middleware + router.param('blockHash', Blocks.blockHashParam); + router.param('height', Blocks.heightParam); + router.param('txHash', Transactions.txHashParam); + // Node routes - router.get('/node', mockResponse); + router.get('/node', NodeStatus.getStatus); // Block routes - router.get('/blocks', mockResponse); - router.get('/blocks/latest', mockResponse); - router.get('/blocks/:blockHash', mockResponse); - router.get('/blocks/:height', mockResponse); - router.get('/blocks/:blockHash/transactions/:txIndex', mockResponse); + router.get('/blocks', Blocks.list); + router.get('/blocks/latest', Blocks.getLatest); + router.get('/blocks/:blockHash([A-Fa-f0-9]{64})', Blocks.get); + router.get('/blocks/:height([0-9]+)', Blocks.get); // Transaction routes router.get('/transactions', mockResponse); - router.get('/transactions/:txHash', mockResponse); - router.post('/transactions/send', mockResponse); - router.get('/transactions/:txHash/addresses', mockResponse); - router.get('/transactions/:txHash/outputs/addresses', mockResponse); - router.get('/transactions/:txHash/inputs/addresses', mockResponse); + router.get('/transactions/:txHash([A-Fa-f0-9]{64})', Transactions.get); + router.post('/transactions/send', Transactions.send); // Input routes router.get('/transactions/:txHash/inputs', mockResponse); @@ -42,6 +53,10 @@ function initRouter(node) { // TODO: check if this is really restful router.get('/addresses/:addresses/utxos', mockResponse); + // error routes + router.get('/blocks/*', Blocks.getBlockError); + router.get('/transactions/*', Transactions.getTxError); + return router; } diff --git a/api/test/data/blocks.js b/api/test/data/blocks.js new file mode 100644 index 00000000..f43d8d67 --- /dev/null +++ b/api/test/data/blocks.js @@ -0,0 +1,15 @@ +'use strict'; + +var bitcore = require('bitcore'); +var Block = bitcore.Block; + +var mockBlocks = {}; +var blockHexs = require('./blocks.json'); +blockHexs.map(function(hex) { + var block = new Block(new Buffer(hex, 'hex')); + return block; +}).forEach(function(block) { + mockBlocks[block.id] = block; +}); + +module.exports = mockBlocks; diff --git a/api/test/data/blocks.json b/api/test/data/blocks.json new file mode 100644 index 00000000..13b81690 --- /dev/null +++ b/api/test/data/blocks.json @@ -0,0 +1,12 @@ +[ + "0100000050120119172a610421a6c3011dd330d9df07b63616c2cc1f1cd00200000000006657a9252aacd5c0b2940996ecff952228c3067cc38d4885efb5a4ac4247e9f337221b4d4c86041b0f2b57100401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020602ffffffff0100f2052a010000004341041b0e8c2567c12536aa13357b79a073dc4444acb83c4ec7a0e2f99dd7457516c5817242da796924ca4e99947d087fedf9ce467cb9f7c6287078f801df276fdf84ac000000000100000001032e38e9c0a84c6046d687d10556dcacc41d275ec55fc00779ac88fdf357a187000000008c493046022100c352d3dd993a981beba4a63ad15c209275ca9470abfcd57da93b58e4eb5dce82022100840792bc1f456062819f15d33ee7055cf7b5ee1af1ebcc6028d9cdb1c3af7748014104f46db5e9d61a9dc27b8d64ad23e7383a4e6ca164593c2527c038c0857eb67ee8e825dca65046b82c9331586c82e0fd1f633f25f87c161bc6f8a630121df2b3d3ffffffff0200e32321000000001976a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac000000000100000001c33ebff2a709f13d9f9a7569ab16a32786af7d7e2de09265e41c61d078294ecf010000008a4730440220032d30df5ee6f57fa46cddb5eb8d0d9fe8de6b342d27942ae90a3231e0ba333e02203deee8060fdc70230a7f5b4ad7d7bc3e628cbe219a886b84269eaeb81e26b4fe014104ae31c31bf91278d99b8377a35bbce5b27d9fff15456839e919453fc7b3f721f0ba403ff96c9deeb680e5fd341c0fc3a7b90da4631ee39560639db462e9cb850fffffffff0240420f00000000001976a914b0dcbf97eabf4404e31d952477ce822dadbe7e1088acc060d211000000001976a9146b1281eec25ab4e1e0793ff4e08ab1abb3409cd988ac0000000001000000010b6072b386d4a773235237f64c1126ac3b240c84b917a3909ba1c43ded5f51f4000000008c493046022100bb1ad26df930a51cce110cf44f7a48c3c561fd977500b1ae5d6b6fd13d0b3f4a022100c5b42951acedff14abba2736fd574bdb465f3e6f8da12e2c5303954aca7f78f3014104a7135bfe824c97ecc01ec7d7e336185c81e2aa2c41ab175407c09484ce9694b44953fcb751206564a9c24dd094d42fdbfdd5aad3e063ce6af4cfaaea4ea14fbbffffffff0140420f00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000", + "0100000006e533fd1ada86391f3f6c343204b0d278d4aaec1c0b20aa27ba0300000000006abbb3eb3d733a9fe18967fd7d4c117e4ccbbac5bec4d910d900b3ae0793e77f54241b4d4c86041b4089cc9b0c01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b010dffffffff0100f2052a01000000434104b27f7e9475ccf5d9a431cb86d665b8302c140144ec2397fce792f4a4e7765fecf8128534eaa71df04f93c74676ae8279195128a1506ebf7379d23dab8fca0f63ac000000000100000001d992e5a888a86d4c7a6a69167a4728ee69497509740fc5f456a24528c340219a000000008b483045022100f0519bdc9282ff476da1323b8ef7ffe33f495c1a8d52cc522b437022d83f6a230220159b61d197fbae01b4a66622a23bc3f1def65d5fa24efd5c26fa872f3a246b8e014104839f9023296a1fabb133140128ca2709f6818c7d099491690bd8ac0fd55279def6a2ceb6ab7b5e4a71889b6e739f09509565eec789e86886f6f936fa42097adeffffffff02000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac00e32321000000001976a9140c34f4e29ab5a615d5ea28d4817f12b137d62ed588ac0000000001000000059daf0abe7a92618546a9dbcfd65869b6178c66ec21ccfda878c1175979cfd9ef000000004a493046022100c2f7f25be5de6ce88ac3c1a519514379e91f39b31ddff279a3db0b1a229b708b022100b29efbdbd9837cc6a6c7318aa4900ed7e4d65662c34d1622a2035a3a5534a99a01ffffffffd516330ebdf075948da56db13d22632a4fb941122df2884397dda45d451acefb0000000048473044022051243debe6d4f2b433bee0cee78c5c4073ead0e3bde54296dbed6176e128659c022044417bfe16f44eb7b6eb0cdf077b9ce972a332e15395c09ca5e4f602958d266101ffffffffe1f5aa33961227b3c344e57179417ce01b7ccd421117fe2336289b70489883f900000000484730440220593252bb992ce3c85baf28d6e3aa32065816271d2c822398fe7ee28a856bc943022066d429dd5025d3c86fd8fd8a58e183a844bd94aa312cefe00388f57c85b0ca3201ffffffffe207e83718129505e6a7484831442f668164ae659fddb82e9e5421a081fb90d50000000049483045022067cf27eb733e5bcae412a586b25a74417c237161a084167c2a0b439abfebdcb2022100efcc6baa6824b4c5205aa967e0b76d31abf89e738d4b6b014e788c9a8cccaf0c01ffffffffe23b8d9d80a9e9d977fab3c94dbe37befee63822443c3ec5ae5a713ede66c3940000000049483045022020f2eb35036666b1debe0d1d2e77a36d5d9c4e96c1dba23f5100f193dbf524790221008ce79bc1321fb4357c6daee818038d41544749127751726e46b2b320c8b565a201ffffffff0200ba1dd2050000001976a914366a27645806e817a6cd40bc869bdad92fe5509188ac40420f00000000001976a914ee8bd501094a7d5ca318da2506de35e1cb025ddc88ac0000000001000000010abad2dc0c9b4b1dbb023077da513f81e5a71788d8680fca98ef1c37356c459c000000004a493046022100a894e521c87b3dbe23007079db4ac2896e9e791f8b57317ba6c0d99a7becd27a022100bc40981393eafeb33e89079f857c728701a9af4523c3f857cd96a500f240780901ffffffff024026ee22010000001976a914d28f9cefb58c1f7a5f97aa6b79047585f58fbd4388acc0cb1707000000001976a9142229481696e417aa5f51ad751d8cd4c6a669e4fe88ac000000000100000001f66d89b3649e0b18d84db056930676cb81c0168042fc4324c3682e252ea9410d0000000048473044022038e0b55b37c9253bfeda59c76c0134530f91fb586d6eb21738a77a984f370a44022048d4d477aaf97ef9c8275bbc5cb19b9c8a0e9b1f9fdafdd39bc85bf6c2f04a4d01ffffffff024041a523010000001976a914955f70ac8792b48b7bd52b15413bd8500ecf32c888ac00f36f06000000001976a91486116d15f3dbb23a2b58346f36e6ec2d867eba2b88ac00000000010000000126c384984f63446a4f2be8dd6531ba9837bd5f2c3d37403c5f51fb9192ee754e010000008b48304502210083af8324456f052ff1b2597ff0e6a8cce8b006e379a410cf781be7874a2691c2022072259e2f7292960dea0ffc361bbad0b861f719beb8550476f22ce0f82c023449014104f3ed46a81cba02af0593e8572a9130adb0d348b538c829ccaaf8e6075b78439b2746a76891ce7ba71abbcbb7ca76e8a220782738a6789562827c1065b0ce911dffffffff02c0dd9107000000001976a91463d4dd1b29d95ed601512b487bfc1c49d84d057988ac00a0491a010000001976a91465746bef92511df7b34abf71c162efb7ae353de388ac0000000001000000011b56cf3aab3286d582c055a42af3a911ee08423f276da702bb67f1222ac1a5b6000000008c4930460221009e9fba682e162c9627b96b7df272006a727988680b956c61baff869f0907b8fb022100a9c19adc7c36144bafe526630783845e5cb9554d30d3edfb56f0740274d507f30141046e0efbfac7b1615ad553a6f097615bc63b7cdb3b8e1cb3263b619ba63740012f51c7c5b09390e3577e377b7537e61226e315f95f926444fc5e5f2978c112e448ffffffff02c0072b11010000001976a914b73e9e01933351ca076faf8e0d94dd58079d0b1f88ac80b63908000000001976a9141aca0bdf0d2cee63db19aa4a484f45a4e26a880c88ac000000000100000001251b187504ea873b2c3915fad401f7a7734cc13567e0417708e86294a29f4f68010000008b4830450221009bef423141ed1ae60d0a5bcaa57b1673fc96001f0d4e105535cca817ba5a7724022037c399bd30374f22481ffc81327cfca4951c7264b227f765fcd6a429f3d9d2080141044d0d1b4f194c31a73dbce41c42b4b3946849117c5bb320467e014bad3b1532f28a9a1568ba7108f188e7823b6e618e91d974306701379a27b9339e646e156e7bffffffff02c00fd103010000001976a914ef7f5d9e1bc6ed68cfe0b1db9d8f09cef0f3ba4a88ac004dd208000000001976a914c22420641cea028c9e06c4d9104c1646f8b1769088ac0000000001000000013486dd5f0a2f3efcc04f64cb03872c021f98ee39f514747ce5336b874bbe47a7010000008b48304502201cadddc2838598fee7dc35a12b340c6bde8b389f7bfd19a1252a17c4b5ed2d71022100c1a251bbecb14b058a8bd77f65de87e51c47e95904f4c0e9d52eddc21c1415ac014104fe7df86d58aafa9246ca6fd30c905714533c25f700e2329b8ecec8aa52083b844baa3a8acd5d6b9732dcb39079bb56ba2711a3580dec824955fce0596a460c11ffffffff02c011f6e1000000001976a91490fac83c9adde91d670dde8755f8b475ab9e427d88acc0f9df15000000001976a91437f691b3e8ee5dcb56c2e31af4c80caa2df3b09b88ac00000000010000000170016bd1274b795b262f32a53003a4714b22b62f9057adf5fbe6ed939003b5190100000089463043022061456499582170a94d6b54308f792e37dad28bf0ed7aa61021f0301d2774d378021f4224b33f707efd810a01dd34ea86d6069cd599cc435513a0eef8c83c137bf7014104a2c95d6b98e745448eb45ed0ba95cf24dd7c3b16386e1028e24a0358ee4afc33e2f0199139853edaf32845d8a42254c75f7dc8add3286c682c650fbd93f0a4a1ffffffff02001bd2b7000000001976a9141b11c6acaa5223013f3a3240fdb024ecd9f8135488ac8023ad18000000001976a914ada27ca87bbaa1ee6fb1cb61bb0a29baaf6da2c988ac000000000100000001c8ff91f031ec6a5aba4baee6549e61dd01f26f61b70e2f1574f24cd680f464ad000000008b48304502210082235e21a2300022738dabb8e1bbd9d19cfb1e7ab8c30a23b0afbb8d178abcf3022024bf68e256c534ddfaf966bf908deb944305596f7bdcc38d69acad7f9c868724014104174f9eef1157dc1ad5eac198250b70d1c3b04b2fca12ad1483f07358486f02909b088bbc83f4de55f767f6cdf9d424aa02b5eeaffa08394d39b717895fc08d0affffffff0200ea3b43000000001976a914fb32df708f0610901f6d1b6df8c9c368fe0d981c88ac800f1777000000001976a914462c501c70fb996d15ac0771e7fc8d3ca3f7201888ac000000000100000001c67323867de802402e780a70e0deba3c708c4d87497e17590afee9c321f1c680010000008a473044022042734b25f54845d662e6499b75ff8529ff47f42fd224498a9f752d212326dbfa0220523e4b7b570bbb1f3af02baa2c04ea8eb7b0fccb1522cced130b666ae9a9d014014104b5a23b922949877e9eaf7512897ed091958e2e8cf05b0d0eb9064e7976043fde6023b4e2c188b7e38ef94eec6845dc4933f5e8635f1f6a3702290956aa9e284bffffffff0280041838030000001976a91436e5884215f7d3044be5d37bdd8c987d9d942c8488ac404b4c00000000001976a91460085d6838f8a44a21a0de56ff963cfa6242a96188ac00000000", + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000", + "01000000aff7e0c7dc29d227480c2aa79521419640a161023b51cdb28a3b0100000000003779fc09d638c4c6da0840c41fa625a90b72b125015fd0273f706d61f3be175faa271b4d4c86041b142dca820c01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0105ffffffff0100f2052a01000000434104354eab02700b9adfae0e1254241a5d50c910c7c43388a91d135049d61608d57b27766ea3e2e00bf33f42e0c866d468d72d70c25a8f458d224a9cfa98f4c61640ac000000000100000001e0c28dbf9f266a8997e1a02ef44af3a1ee48202253d86161d71282d01e5e30fe010000008b48304502200ce17394660867b7c90f89d995b1433fe574822775c0d92ac26098faf401b571022100e76cf491ec73c6ef748bc29cdd0e595fa7d1bfe014fd9306305f27650bcb19b2014104ea10914b4fef0914d6afcf334f16f215660e3cac5a97624d6a32b4b97021d73330e003b1dc6fbaa86b4f493caccbb6dc6f7c695ece852e8abf2820afba008f6dffffffff02c0320a03000000001976a9146168f1368ef3e45fd53166199499020a4b9bf91f88ac4077f86d000000001976a91478e32fd3928cfa1cfbe43595311a973292c6accc88ac000000000100000001201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674000000008b48304502203506c7af67bd72847030faf8a9f9e7c0012f127415f94ee7b87f72fef7a43dbc022100b28ad13e561a3bab5b3f6b9301d00ae77a662dba550101fa14cd3420246e63c40141049112bfbe88ce0b3d0813f18e3cc6078f6211166298dc4c65fd0fb1303a9431df137617a6f7bde8411746f08d88ac2dc5ba9303caea948a531667bad075b97c99ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac80969800000000001976a9149d871517162804ec48595ac97a3f6e3af719548e88ac0000000001000000015310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd000000008b483045022100f1f64f345f30c3f0323de5f2ac288f83185253769a8f65a918caec7047f4504d02207a0182d0b8bbfac9542df4787b0d96da091780df96fed2a776c5a01e77df63ce0141041ba340ee313ae241b8221c97c46b9adef9f2f0e8a4a861011f1fccb8b62f2b1cfbe98df09176cc00f64f96a15bdb247bdd8bc4b27060948c5a60fd0b92e4085effffffff0240420f00000000001976a914dfb5bd621d66e957cd642bc8d65b5fd318a350ec88ac00093d00000000001976a914e2f2c2f37cbddbc64cbf6f1f028c2c8a7739010f88ac000000000100000001c27e2776254a0acdc9c18bfd2666a3857183c032ba058cdc7be22b44adf59699010000008b483045022100a594f3a88125883569d5d69176d754e845bba058a92e87c8daf7131a1b34fc3c02202b50bce7e68c78713eb214dd05847a0742740ac330c5cfe9e688af8d3a6b2cf7014104ddc05b55d9d3acca503d2aebc4519141ef38ebea8f7b950b3142db71b87a256d44cc18738d436ad6792a44676a6181c2ea390a21be30b35b60d04b5a26840565ffffffff02c086fd6a000000001976a9142b5cc97c3f95dc20beae095a6fe2274c3948570588ac80f0fa02000000001976a91456f000ac3ee604a7c2dabd4e82f16d363dcd298288ac000000000100000001758713310361270b5ec4cae9b0196cb84fdb2f174d29f9367ad341963fa83e56010000008b483045022100d7b8759aeffe9d829a5df062420eb25017d7341244e49cfede16136a0c0b8dd2022031b42048e66b1f82f7fa99a22954e2709269838ef587c20118e493ced0d63e21014104b9251638d1475b9c62e1cf03129c835bcd5ab843aa0016412e8b39e3f8f7188d3b59023bce2002a2e409ea070c7070392b65d9ae8c8631ae2672a8fbb4f62bbdffffffff02404b4c00000000001976a9143675767783fdf1922f57ab4bb783f3a88dfa609488ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000123ef5b8dc3656f80d3716299a56be91d75c9bb754b675bd1b127ecde53b743b6000000008b48304502207e99923bd10fa2017c5f439c60695986ec442af1c52a3310b22e68b4ee6779e4022100aa84b7321424541075c05a0244a9973967ff07752c0cebe4ca2a9bdf0ecfe17c014104ca088e0d674c67404c16a7d49ea59b467f09daf16dfab1baeac6bbcd2f2674ad670da0e01a12cdbff4e91d46b5994d583e476910d8db15e84bb9a77460164e5effffffff0240a5ae02000000001976a914b55dd29fed068ccc1bc17312559953f6583ee7e488ac80e14e68000000001976a91444bce51126d64d006104a26f44f1597e4937452588ac0000000001000000012376bfcaa5bc0c3864c0ab20f2f1a2301f8d5408be2924721740681802f81a97000000008b4830450220377c24b01eb0e1cb51fff57b8ae814f43b03429ad70be3b871e8120f17079250022100e34787dc7fab91d9802ade84847c7b1308b5cc2ff8e827328f3271ba49b219480141043cb62688ba96924898f96f9a27328364ab4109407ab47522b1203d7b10364785e4901d6bdf5ec0b0ba4c56deaba832a93e74251176812c1038965628bf017fa2ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000190ac85c88338b5ee4700b4131d17872a0b26806f123ceae83ec6d46a90b209fe010000008a4730440220767e105c213d3d823a5fed7ec85274770dfda68945d9e346e3d1460c2a9d715e02207d46d23c051531e30d8414951190d43e5af46cfb0a769dc119aacd13a8e33ec50141043d82b7876393cf7f46a1b63f911f38c09b3cf1c8edcf0385ce2b70ce52f0356c44c713493cfeff1042aa1bfce67540e76d76c83769b92c8ab6bf5c345562ac85ffffffff0280b41d67000000001976a914192beb072189022800ecc07211938f7948683c1688ac002d3101000000001976a91494325f0965dcd1c23b3b9f7ef6e93ae4d1a7c02b88ac00000000010000000127e706a02efbc6aff715083d3e26bf1197458e791cdfb29fc07309a5cc74a5d9000000008c493046022100b16337778e99a658ee7355e9d32d7eeb090ed6b7decb6041e8ae60bc1765bda4022100afe1ac3a0c8d60abf7dac9101ea94c804d7860899f5561a40a9335a6927fc6e10141048333f4c6691ae094c741d13f34303ac65c5ce09833ea5e614886ce3b267e713fe8f941e8da29fe746233554f94c18f734404f3e941d0bef02da3beaeb9a8a535ffffffff02c0ea2101000000001976a914417d48fe8e9bb1971c4a0e21c387a41ae200630488acc0c9fb65000000001976a9147e19933a6a86b7f7fe4a4facf5d23d2127d55a5488ac0000000001000000017b00c49d3193b1f565057420f57a1bf41c5396799081980c4e9784cf3b4823d5010000008c493046022100c0f8dc4111c7def22bd1cd5e5b16a63b9f03e4d64d6e24a986c765930e2680e2022100e30b50365f01cd6d4df11c8a530fba52f40acd6ad8fc5436cc836291df8d38b80141047101cf453ed5ae5e3863588a5c8f65ee633bf610c0e73100decf145f4a1586d64d4f6599c9fa563b059fe43cd3b34154de9fbdcd8d4cb189a38ce6493bce043bffffffff024021e964000000001976a914ff75b16b44247550e51d7d4ed7e80e23acfdca1188ac80a81201000000001976a914605e62db0e9dcc421f1b5936f5b7c4dfff7a748288ac0000000001000000018cc7bbcc435470f3f767348210b707cb887cb3fc46c2dd16207738db1c72e722000000008a473044022024354d328e6a84717e6ff71c5d39ffaf21bb2ba3278acabbb793ed90cad1fa7a02204e36ba837fd0c49fbd4e1045bb18a4556bb7fa0757a5651de40a64798227e52e0141040419507a674c45c65b76192cac56c409ac6c4fe4b8f292470d10b689bfb0df34d40037023507dce82ba51daf7c60c71d4100fe83602428f0bf516ed22c01a224ffffffff02809fd500000000001976a914d5dc1f4d24658896095b777b4f57d9eaab3d1bbe88acc0811364000000001976a91411106981411de25053a8182ae4a26365d33950a888ac00000000", + "01000000e1c5ba3a6817d53738409f5e7229ffd098d481147b002941a7a002000000000077ed2af87aa4f9f450f8dbd15284720c3fd96f565a13c9de42a3c1440b7fc6a50e281b4d4c86041b08aecda20601000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0143ffffffff0100f2052a01000000434104e55c9ea4f114dbc3b40451624a9aab17fd5b353b9d94aae9bacef2c6fd8ea52c241001506cef00fe6b729fa33ddd3209a1d706065444e14c636e4ea4ef76917bac000000000100000001d39d924c396333e14353cdc4dbc3a7225bd2d854a650a54c2afac7a775da8e7d010000008b48304502207c7c9dc9ef9ec8adbc32b7d4d3ccf0c08e12d3bde2f9630d70ad36a503819b40022100b7c6198d70fe98e3f72795a98e7d3598d19ac61a43b0d4fa76808a1597340459014104bdf3c1f9d797980073bc85c2ac3f2db68c1d44fdb8bf06da5d1b0084db1f6d7e1192519d6a329c2037e00b3251423577159a1d2dde7fe9575c3e2f09e2b8dc25ffffffff02c0665c63000000001976a914f0c4fd57f350fe097151c92f35b56fa4123e170688ac001bb700000000001976a9140c06e0a869292ca77b0c0cf95bd4d8d1f18499ab88ac00000000010000000199db128ad1e9247b8f9182ff57c45949230ff2e9c3f1dd26e6f1c9799ae563c7000000008b48304502203153950a39db89129739d79655e18e844910fc390df3e757444608d68ab7c802022100d679e030889cb2467451c172f8d63c58e85be633f1acdbf85fab87ed95c9eee9014104d0ed1abeba4ecb8e1cdeb2531e0b9adda7541482b60c86e637af94ec82c3aefa777ea9ea50d5242504d19fa4a0500c072db5e5addee09d6808b57d75dd1dd48bffffffff02008eb462000000001976a9143f6a97f34f8c5f6cc697d9650498f3f27060489a88acc0d8a700000000001976a9143478fffab9d7e8d5ec19199e46dcfcf6c6ecb2cf88ac0000000001000000016b51f541cc5a50dd61d19eb94523b4c72117aa0c4e41f57329f9ee7a643eea80000000008a473044022078147784c149d36b8b6ec5434b26e325757e5703ddbd5ef98eea04eac44d23a802203401a87711ec6b33970c93214d5b842733adf95251b869229a08e2e490df5caf01410440da7819054bfdfbb284e498de2ec7bfa6cbf7af7c930bc56d0b0c021a32e460b389aec2c06f72c4b20aab4685fcf626445e910914fc578faf3ad0a7116d8ca4ffffffff02c0d8a700000000001976a91434931d97bd14e58d50b42e8f10d082649a55ccd088ac40b50c62000000001976a9148e4960528daa1d33571d3e1fda6344ac1b75902f88ac000000000100000001d38c4935a387c0cd0658bddaf9553cdf743221e248cbc02e360ace70fdee721b010000008b4830450221009fce94f4489c0f412d181780a5131cf2bd8d926c38878bb520047e4498e85292022078cca9f887ff4c143800eca06c3faa970b65e14013abe1bb45d548e9c6e3825a014104d987807bdac7bc5935067fa4704e87b6a45c3451f4a0b939a513d3cddc1177a729a5d62195abb94b0c532f616b5e5f0f4b09c15008f9470bf5a8c91e01d5995fffffffff02c0d8a700000000001976a914795c679389d97af7ee450f1237bd8944d03b4bff88ac80dc6461000000001976a914526a1a0926fb3d9df1f7ab101075553106f8d84e88ac0000000001000000017361e6f786448f2ccaded77b384ae32d3172b804a69c7a7c2d9ed5f67033e123010000008b48304502202a910b7791aba4e1e5d33e240097fa9fe1bf0fb3dfd30535cb6ed572da7da22c022100eb9327061250600e958ba40e68e58501bfa09071591d60f19dbe59c3e31618d2014104e1f4bafa5beb89a1c843772e8e977505b4781eb8b3440b28ed18e18db76a68045627d8324a061cef105f2f0bce3eb47f89cdc38bf823a227f45d7f66376191b2ffffffff02c003bd60000000001976a9142fb71ee16dd498ac19f9edb3a349cd743dd3110e88acc0d8a700000000001976a9143ac5edbc9d144389128633d603220c8cea0f826a88ac00000000", + "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000", + "0100000045dc58743362fe8d8898a7506faa816baed7d391c9bc0b13b0da00000000000021728a2f4f975cc801cb3c672747f1ead8a946b2702b7bd52f7b86dd1aa0c975c02a1b4d4c86041b7b47546d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b02bf07ffffffff0100f2052a01000000434104f59a6d2d11830b2eb4b2338f20d1ec9d1f69ffa943b5faab5bb42bf85114d8b9d0fc79afd9abcf09ca7790786a57a0df0aa66eedb09ee5ecc9961d4e1c4a2dc8ac00000000", + "0100000060cd109177b7d41c06bc57b4c39c79227766bd0408c1828a959b0000000000009551f80492d880bd8d65411ba54e6d1ef7482373f72c855b441d2ac45da3c548812a1b4d4c86041b0b014de80101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0145ffffffff0100f2052a01000000434104ff034c75ce5b1ea1238b658bd77370fcaaaadafd686fe46638296ce20d976310eac157175351758b4310bcc302eb4a0f772751553c7b7fb6b6df21c4425ef1f2ac00000000", + "010000009b9c3121e0643c696ae654cb0d4e3fd05ce74edfa060a3901723010000000000c556c926546e582aa5d0906264940f55aca18b9fdd020eefa22333288891057a862b1b4d4c86041b03a34c640201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0147ffffffff0100f2052a01000000434104ad3b4c6ee28cb0c438c87b4efe1c36e1e54c10efc690f24c2c02446def863c50e9bf482647727b415aa81b45d0f7aa42c2cb445e4d08f18b49c027b58b6b4041ac000000000100000001bd06367d15f5699ab2231160de4c74a4a8cfae4a97c1fc5a77a02aead8e391cb000000008b483045022100a1f2df66d173e668849694bd2c0dc77162278f34902483d55fb16631e39e37f10220157636faa19568e04f82dd477e9e6a10fefe99492a70ec23b338c633a6f28f5d014104a34f5f40605dd7d2b11a0ef3c9ab32be64318c2aa34b3a924f16ee8a9a0eabd8b7183bd8e1acb0569f3a6b4cfc912c575d0d83bc2ba7035fc59991205432479cffffffff0140420f00000000001976a9147d878427c2cffbbb117200ca85689269f73e7fcb88ac00000000", + "01000000e265566c8c4a61bb621cf14de2ecabb973ddb394d4acc477b1df0200000000004f98c7a27f827e74654a06fd2eab92f175568f9a04d2b3bd72a370ac4b7e0a9a062d1b4d4c86041b503ccc8d0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b014affffffff0100f2052a01000000434104785e94ee05480f6aeb5b55955cc7e8e99da1e29ce73e7becf27c6976c36613ae148206e191b645eb49667feed26ec1c86877679583f98bc808098a1041e0f681ac000000000100000001cb48458e98523326bed810d8beb6ec236d626bbf999f401511da2bdeb27bd005000000008b48304502204872f54f3f0eeb1e7fc1aa0e117df0bc94255d6042dc3f5fd899c9ce23cfbf080221009515b5764d2874d90445b2bc92791bccd166ededcd95ae065ccf09b389e46d070141040555f89aae042d0d6bd56a0e6b6dbea694d2f3e62d996bbfbb03357ef2d2e21c05ed725dbe73c0327bfb621ca2a1d1e7af65c022c1fad40f0033b27c30ff3bdaffffffff02404b4c00000000001976a9145e31299838d56390e79548fb34c20c0f0e97e3d888ac40b9cb37030000001976a9141083c63b6e3d9fb9d6019b85a9ae1c29209e4b5588ac00000000" +] diff --git a/api/test/data/transactions.js b/api/test/data/transactions.js new file mode 100644 index 00000000..4317a081 --- /dev/null +++ b/api/test/data/transactions.js @@ -0,0 +1,17 @@ +'use strict'; + +var bitcore = require('bitcore'); +var Block = bitcore.Block; + +var mockTransactions = {}; +var blockHexs = require('./blocks.json'); +blockHexs.map(function(hex) { + var block = new Block(new Buffer(hex, 'hex')); + return block; +}).forEach(function(block) { + block.transactions.forEach(function(tx) { + mockTransactions[tx.id] = tx; + }); +}); + +module.exports = mockTransactions; diff --git a/api/test/http.js b/api/test/http.js index 0566540b..e4d2951d 100644 --- a/api/test/http.js +++ b/api/test/http.js @@ -10,6 +10,9 @@ var BitcoreHTTP = require('../lib/http'); describe('BitcoreHTTP', function() { // mocks + var opts = { + port: 1234 + }; var nodeMock; beforeEach(function() { nodeMock = new EventEmitter(); @@ -25,7 +28,7 @@ describe('BitcoreHTTP', function() { }); }); it('starts', function() { - var http = new BitcoreHTTP(nodeMock); + var http = new BitcoreHTTP(nodeMock, opts); http.start.bind(http).should.not.throw(); }); diff --git a/api/test/routes.js b/api/test/routes.js index 70d987aa..a489476f 100644 --- a/api/test/routes.js +++ b/api/test/routes.js @@ -29,12 +29,5 @@ describe('BitcoreHTTP routes', function() { .expect(200) .expect('bitcore-node API', cb); }); - it('blocks', function(cb) { - agent.get('/v1/blocks/') - .expect(200) - .expect({ - 'message': 'This is a mocked response' - }, cb); - }); }); diff --git a/api/test/v1/blocks.js b/api/test/v1/blocks.js new file mode 100644 index 00000000..16ba48f0 --- /dev/null +++ b/api/test/v1/blocks.js @@ -0,0 +1,147 @@ +'use strict'; + +var chai = require('chai'); +var should = chai.should(); +var request = require('supertest'); + +var EventEmitter = require('eventemitter2').EventEmitter2; +var Promise = require('bluebird'); +Promise.longStackTraces(); +var bitcore = require('bitcore'); +var _ = bitcore.deps._; + +var BitcoreHTTP = require('../../lib/http'); +var BitcoreNode = require('../../../'); +var mockBlocks = require('../data/blocks'); + +Object.values = function(obj) { + var vals = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + vals.push(obj[key]); + } + } + return vals; +}; + +describe('BitcoreHTTP v1 blocks routes', function() { + + // mocks + var b1 = mockBlocks[Object.keys(mockBlocks)[0]]; + var firstBlock = mockBlocks[Object.keys(mockBlocks).splice(0, 1)[0]]; + var secondBlock = mockBlocks[Object.keys(mockBlocks).splice(1, 1)[0]]; + var lastBlock = mockBlocks[Object.keys(mockBlocks).splice(-1)[0]]; + var blockForHash = function(hash) { + return mockBlocks[hash]; + }; + var last3 = Object.keys(mockBlocks).splice(-3).map(blockForHash); + var some2 = Object.keys(mockBlocks).splice(2,2).map(blockForHash); + var nodeMock, app, agent; + var blockList = Object.values(mockBlocks); + beforeEach(function() { + nodeMock = new EventEmitter(); + nodeMock.getBlock = function(blockHash) { + var block; + if (typeof blockHash === 'number') { + var height = blockHash; + block = mockBlocks[Object.keys(mockBlocks)[height - 100000]]; + } else { + block = mockBlocks[blockHash]; + } + if (_.isUndefined(block)) { + return Promise.reject(new BitcoreNode.errors.Blocks.NotFound(blockHash)); + } + return Promise.resolve(block); + + }; + nodeMock.getLatestBlock = function() { + return Promise.resolve(lastBlock); + }; + nodeMock.listBlocks = function(from, to, offset, limit) { + var start = from - 1e5; + var end = to - 1e5; + var section = blockList.slice(start, end); + return Promise.resolve(section.slice(offset, offset + limit)); + }; + app = new BitcoreHTTP(nodeMock).app; + agent = request(app); + }); + + describe('/blocks', function() { + it('works with default parameters', function(cb) { + agent.get('/v1/blocks/') + .expect(200) + .expect(JSON.stringify(blockList), cb); + }); + it('fails with to= to "from"', cb); + }); + it('works with to/from parameters', function(cb) { + agent.get('/v1/blocks/?from=100000&to=100001') + .expect(200) + .expect(JSON.stringify([firstBlock]), cb); + }); + it('works with limit/offset parameters', function(cb) { + agent.get('/v1/blocks/?limit=1&offset=1') + .expect(200) + .expect(JSON.stringify([secondBlock]), cb); + }); + it('works with all parameters', function(cb) { + agent.get('/v1/blocks/?from=100005&to=100020&limit=3&offset=2') + .expect(200) + .expect(JSON.stringify(last3), cb); + }); + it('works with all parameters 2', function(cb) { + agent.get('/v1/blocks/?from=100000&to=100005&limit=2&offset=2') + .expect(200) + .expect(JSON.stringify(some2), cb); + }); + }); + describe('/blocks/latest', function() { + it('returns latest block', function(cb) { + agent.get('/v1/blocks/latest') + .expect(200) + .expect(lastBlock.toJSON(), cb); + }); + }); + describe('/blocks/:blockHash', function() { + it('fails with invalid blockHash', function(cb) { + agent.get('/v1/blocks/abad1dea') + .expect(422) + .expect('/v1/blocks/ parameter must be a 64 digit hex or block height integer', cb); + }); + it('returns 404 with non existent block', function(cb) { + agent.get('/v1/blocks/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000') + .expect(404) + .expect('Block with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb); + }); + Object.keys(mockBlocks).forEach(function(hash) { + var block = mockBlocks[hash]; + it('works with valid blockHash ...' + hash.substring(hash.length - 8), function(cb) { + agent.get('/v1/blocks/' + hash) + .expect(200) + .expect(block.toJSON(), cb); + }); + }); + }); + describe('/blocks/:height', function() { + it('fails with invalid height', function(cb) { + agent.get('/v1/blocks/-15') + .expect(422) + .expect('/v1/blocks/ parameter must be a 64 digit hex or block height integer', cb); + }); + it('returns 404 with non existent block', function(cb) { + agent.get('/v1/blocks/876543') + .expect(404) + .expect('Block with height 876543 not found', cb); + }); + it('works with valid height', function(cb) { + agent.get('/v1/blocks/100000') + .expect(200) + .expect(b1.toJSON(), cb); + }); + }); + +}); diff --git a/api/test/v1/node.js b/api/test/v1/node.js new file mode 100644 index 00000000..16a5a375 --- /dev/null +++ b/api/test/v1/node.js @@ -0,0 +1,39 @@ +'use strict'; + +var chai = require('chai'); +var should = chai.should(); +var request = require('supertest'); + +var EventEmitter = require('eventemitter2').EventEmitter2; +var Promise = require('bluebird'); +Promise.longStackTraces(); + +var BitcoreHTTP = require('../../lib/http'); + +describe('BitcoreHTTP v1 node routes', function() { + + // mocks + var nodeMock, app, agent; + beforeEach(function() { + nodeMock = new EventEmitter(); + nodeMock.status = { + sync: 0.75, + peer_count: 8, + version: 'test' + }; + nodeMock.getStatus = function() { + return Promise.resolve(nodeMock.status); + }; + app = new BitcoreHTTP(nodeMock).app; + agent = request(app); + }); + + describe('/node', function() { + it('works', function(cb) { + agent.get('/v1/node/') + .expect(200) + .expect(nodeMock.status, cb); + }); + }); + +}); diff --git a/api/test/v1/transactions.js b/api/test/v1/transactions.js new file mode 100644 index 00000000..f027153e --- /dev/null +++ b/api/test/v1/transactions.js @@ -0,0 +1,112 @@ +'use strict'; + +var chai = require('chai'); +var should = chai.should(); +var request = require('supertest'); + +var bitcore = require('bitcore'); +var _ = bitcore.deps._; +var Transaction = bitcore.Transaction; +var EventEmitter = require('eventemitter2').EventEmitter2; +var Promise = require('bluebird'); +Promise.longStackTraces(); + +var BitcoreHTTP = require('../../lib/http'); +var BitcoreNode = require('../../../'); +var mockTransactions = require('../data/transactions'); + +describe('BitcoreHTTP v1 transactions routes', function() { + + // mocks + var mockValidTx = new Transaction(); + var t1 = mockTransactions[Object.keys(mockTransactions)[0]]; + var nodeMock, app, agent; + beforeEach(function() { + nodeMock = new EventEmitter(); + nodeMock.getTransaction = function(txHash) { + var tx = mockTransactions[txHash]; + if (_.isUndefined(tx)) { + return Promise.reject(new BitcoreNode.errors.Transactions.NotFound(txHash)); + } + return Promise.resolve(tx); + }; + nodeMock.broadcast = function(tx) { + if (mockTransactions[tx.id]) { + return Promise.reject(new BitcoreNode.errors.Transactions.CantBroadcast(tx.id)); + } + return Promise.resolve(); + }; + app = new BitcoreHTTP(nodeMock).app; + agent = request(app); + }); + + describe('/transactions', function() { + it('works with default parameters', function(cb) { + agent.get('/v1/transactions/') + .expect(200) + .expect({ + 'message': 'This is a mocked response' + }, cb); + }); + }); + describe('/transactions/:txHash', function() { + it('fails with invalid txHash', function(cb) { + agent.get('/v1/transactions/abad1dea') + .expect(422) + .expect('/v1/transactions/ parameter must be a 64 digit hex', cb); + }); + it('returns 404 with non existent transaction', function(cb) { + agent.get('/v1/transactions/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000') + .expect(404) + .expect('Transaction with id 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b600000000 not found', cb); + }); + Object.keys(mockTransactions).forEach(function(hash) { + it('works with valid txHash ...' + hash.substring(hash.length - 8), function(cb) { + agent.get('/v1/transactions/' + hash) + .expect(200) + .expect(mockTransactions[hash].toJSON(), cb); + }); + }); + }); + describe('/transactions/send', function() { + it('fails with invalid data type', function(cb) { + agent.post('/v1/transactions/send') + .send('some random data') + .expect(422) + .expect('/v1/transactions/send parameter must be a raw transaction hex', cb); + }); + it('fails with invalid data format', function(cb) { + agent.post('/v1/transactions/send') + .send({ + 1: 2 + }) + .expect(422) + .expect('/v1/transactions/send parameter must be a raw transaction hex', cb); + }); + it('fails with valid data format, invalid raw tx', function(cb) { + agent.post('/v1/transactions/send') + .send({ + raw: '00abad1d3a' + }) + .expect(422) + .expect('/v1/transactions/send parameter must be a raw transaction hex', cb); + }); + it('works with valid tx', function(cb) { + agent.post('/v1/transactions/send') + .send({ + raw: mockValidTx.uncheckedSerialize() + }) + .expect(200) + .expect('Transaction broadcasted successfully', cb); + }); + it('fails with invalid tx', function(cb) { + agent.post('/v1/transactions/send') + .send({ + raw: t1.uncheckedSerialize() + }) + .expect(422) + .expect('Unable to broadcast transaction 8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87', cb); + }); + }); + +}); diff --git a/index.js b/index.js index 3ad4398a..51e4e9f8 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,10 @@ 'use strict'; -var config = require('config'); -var BitcoreNode = require('./lib/node.js'); +var BitcoreNode = require('./lib/node'); if (require.main === module) { + var config = require('config'); var node = BitcoreNode.create(config.get('BitcoreNode')); node.start(); node.on('error', function(err) { @@ -16,4 +16,7 @@ if (require.main === module) { }); } + +BitcoreNode.errors = require('./lib/errors'); + module.exports = BitcoreNode; diff --git a/lib/errors.js b/lib/errors.js new file mode 100644 index 00000000..fb293fb3 --- /dev/null +++ b/lib/errors.js @@ -0,0 +1,26 @@ +'use strict'; + +var spec = { + name: 'BitcoreNode', + message: 'Internal Error on BitcoreNode', + errors: [{ + name: 'Transactions', + message: 'Internal Transactions error on BitcoreNode', + errors: [{ + name: 'NotFound', + message: 'Transaction {0} not found' + }, { + name: 'CantBroadcast', + message: 'Unable to broadcast transaction {0}' + }] + }, { + name: 'Blocks', + message: 'Internal Blocks error on BitcoreNode', + errors: [{ + name: 'NotFound', + message: 'Block {0} not found' + }] + }] +}; + +module.exports = require('bitcore').errors.extend(spec);