diff --git a/app/controllers/network.js b/app/controllers/network.js index 326782f244b7c5e5244714f894cdcc08da6d2d5b..b8e84ac75180cac5ac4a7440ec0f16b33a5867bc 100644 --- a/app/controllers/network.js +++ b/app/controllers/network.js @@ -40,8 +40,12 @@ function NetworkBinding (server) { peers.forEach(function (peer){ map[peer.hash] = Peer.statics.peerize(peer).json(); }); + if (peers.length == 0) { + done(constants.ERRORS.PEER_NOT_FOUND); + } done(null, map); - }); + }) + .catch(done); }); }); diff --git a/app/lib/constants.js b/app/lib/constants.js index 07408574b7c0134dc4bc10251db67ca442b6bb94..562e5a411a5bedbcfdfc800beab6869daf1821b5 100644 --- a/app/lib/constants.js +++ b/app/lib/constants.js @@ -58,7 +58,8 @@ module.exports = { MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }}, NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }}, NO_CURRENT_BLOCK: { httpCode: 404, uerr: { ucode: 2010, message: "No current block" }}, - BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }} + BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }}, + PEER_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2012, message: "Peer not found" }} }, DEBUG: { diff --git a/app/lib/streams/bma.js b/app/lib/streams/bma.js index 0835e476eaf9f9615c8aa49dbf81fbaa75b0a967..2a35d73b6661505895af80922db9ccb6688e0dc3 100644 --- a/app/lib/streams/bma.js +++ b/app/lib/streams/bma.js @@ -84,7 +84,7 @@ module.exports = function(server, interfaces, httpLogs) { answerForGetP( '/blockchain/with/tx', blockchain.with.tx, dtos.Stat); answerForGetP( '/blockchain/branches', blockchain.branches, dtos.Branches); answerForGetP( '/network/peering', net.peer, dtos.Peer); - answerForGetP( '/network/peering/peers', net.peersGet, dtos.Merkle); + answerForGetP( '/network/peering/peers', net.peersGet, dtos.MerkleOfPeers); answerForPostP( '/network/peering/peers', net.peersPost, dtos.Peer); answerForGetP( '/network/peers', net.peers, dtos.Peers); answerForPostP( '/wot/add', wot.add, dtos.Identity); diff --git a/app/lib/streams/dtos.js b/app/lib/streams/dtos.js index 0a5fcbb585a93978dc7213ae606400f4f2b19c5a..a69a5a1662349d6378a3b00e9cb021760c337133 100644 --- a/app/lib/streams/dtos.js +++ b/app/lib/streams/dtos.js @@ -141,7 +141,7 @@ dtos.Peers = { "peers": [dtos.DBPeer] }; -dtos.Merkle = { +dtos.MerkleOfPeers = { "depth": Number, "nodesCount": Number, "leavesCount": Number, @@ -149,7 +149,7 @@ dtos.Merkle = { "leaves": [String], "leaf": { "hash": String, - "value": {} + "value": dtos.DBPeer } }; diff --git a/app/service/MerkleService.js b/app/service/MerkleService.js index 296f196128ec97d8dd355b1c10f04f045e1af755..6dba7872744095f9857d1beb88d5544b3ed11b85 100644 --- a/app/service/MerkleService.js +++ b/app/service/MerkleService.js @@ -20,6 +20,7 @@ module.exports = { var hashes = [req.query.leaf]; // This code is in a loop for historic reasons. Should be set to non-loop style. valueCB(hashes, function (err, values) { + if (err) return done(err); hashes.forEach(function (hash){ json.leaf = { "hash": hash, diff --git a/install.sh b/install.sh index a2fa0b6b1dfb443a095e4c9ea14068d66566d93a..2a5b38a6e85cc303d1ef438926b6c52d959ac973 100644 --- a/install.sh +++ b/install.sh @@ -11,7 +11,7 @@ if [ -z "$UCOIN_DIR" ]; then fi ucoin_latest_version() { - echo "v0.13.0" + echo "v0.13.1" } ucoin_repo_url() { diff --git a/package.json b/package.json index d3ad1f57882e102d98e74d7b94e0458b9d37b728..06b6c7f9b15addfc8239113c4d04b980234fe686 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ucoin", - "version": "0.13.0", + "version": "0.13.1", "engines": { "node": ">=4.2.0", "npm": ">=2.11" diff --git a/test/integration/branches.js b/test/integration/branches.js index 614406f35578a9583d1f8f5fe7ae92d15325e027..e35399de231e9d33444d46bfd9296a1557dc1e13 100644 --- a/test/integration/branches.js +++ b/test/integration/branches.js @@ -225,7 +225,7 @@ describe("Branches", function() { it('should have a 3 blocks fork window size', function() { return expectAnswer(rp('http://127.0.0.1:7778/node/summary', { json: true }), function(res) { res.should.have.property('ucoin').property('software').equal('ucoind'); - res.should.have.property('ucoin').property('version').equal('0.13.0'); + res.should.have.property('ucoin').property('version').equal('0.13.1'); res.should.have.property('ucoin').property('forkWindowSize').equal(3); }); }); diff --git a/test/integration/network.js b/test/integration/network.js new file mode 100644 index 0000000000000000000000000000000000000000..6a7e1f7d7abf8812dfb8d99b2a184815192a8db7 --- /dev/null +++ b/test/integration/network.js @@ -0,0 +1,142 @@ +"use strict"; + +var co = require('co'); +var _ = require('underscore'); +var ucoin = require('./../../index'); +var bma = require('./../../app/lib/streams/bma'); +var user = require('./tools/user'); +var rp = require('request-promise'); +var httpTest = require('./tools/http'); +var commit = require('./tools/commit'); +var sync = require('./tools/sync'); +var node = require('./tools/node'); + +var expectJSON = httpTest.expectJSON; +var expectHttpCode = httpTest.expectHttpCode; +var expectAnswer = httpTest.expectAnswer; + +var MEMORY_MODE = true; +var commonConf = { + ipv4: '127.0.0.1', + remoteipv4: '127.0.0.1', + currency: 'bb', + httpLogs: true, + forksize: 3, + parcatipate: false, // TODO: to remove when startGeneration will be an explicit call + sigQty: 1 +}; + +var s1 = node({ + memory: MEMORY_MODE, + name: 'bb33' +}, _.extend({ + port: '20501', + remoteport: '20501', + pair: { + pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', + sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP' + }, + participate: false, rootoffset: 10, + sigQty: 1, dt: 0, ud0: 120 +}, commonConf)); + +var s2 = node({ + memory: MEMORY_MODE, + name: 'bb12' +}, _.extend({ + port: '20502', + remoteport: '20502', + pair: { + pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', + sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F' + } +}, commonConf)); + +var cat = user('cat', { pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'}, { server: s1 }); +var toc = user('toc', { pub: 'DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', sec: '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F'}, { server: s1 }); + +var now = Math.round(new Date().getTime()/1000); + +describe("Network Merkle", function() { + + before(function() { + + return co(function *() { + yield s1.startTesting(); + yield s2.startTesting(); + let peer1 = yield s1.peeringP(); + yield s2.submitPeerP(peer1); + }); + }); + + describe("Server 1 /network/peering", function() { + + it('/peers?leaves=true', function() { + return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaves=true', { json: true }), (res) => { + res.should.have.property('depth').equal(0); + res.should.have.property('nodesCount').equal(0); + res.should.have.property('leavesCount').equal(1); + res.should.have.property('root').equal('CB9F165229579D66447F4C5A0EABAD6F51985387'); + res.should.have.property('leaves').length(1); + res.leaves[0].should.equal('CB9F165229579D66447F4C5A0EABAD6F51985387'); + }); + }); + + it('/peers?leaf=CB9F165229579D66447F4C5A0EABAD6F51985387', function() { + return expectAnswer(rp('http://127.0.0.1:20501/network/peering/peers?leaf=CB9F165229579D66447F4C5A0EABAD6F51985387', { json: true }), (res) => { + res.should.have.property('depth').equal(0); + res.should.have.property('nodesCount').equal(0); + res.should.have.property('leavesCount').equal(1); + res.should.have.property('root').equal('CB9F165229579D66447F4C5A0EABAD6F51985387'); + res.should.have.property('leaves').length(0); + res.should.have.property('leaf').have.property('hash').equal('CB9F165229579D66447F4C5A0EABAD6F51985387'); + res.should.have.property('leaf').have.property('value'); + res.should.have.property('leaf').have.property('value').have.property('pubkey').equal('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd'); + res.should.have.property('leaf').have.property('value').have.property('block').equal('0-DA39A3EE5E6B4B0D3255BFEF95601890AFD80709'); + res.should.have.property('leaf').have.property('value').have.property('signature').equal('iH35xyF95GMvXWKewJHhShkXNppU2/0p1EbQErgSbBipq6A2Ux9YwzSoPXXnCQCTrBSMKbc/KSDgtRuCmAIoBQ=='); + res.should.have.property('leaf').have.property('value').have.property('status').equal('UP'); + res.should.have.property('leaf').have.property('value').have.property('currency').equal('bb'); + res.should.have.property('leaf').have.property('value').have.property('endpoints').length(1); + res.leaf.value.endpoints[0].should.equal('BASIC_MERKLED_API 127.0.0.1 20501'); + }); + }); + }); + + describe("Server 2 /network/peering", function() { + + it('/peers?leaves=true', function() { + return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaves=true', { json: true }), (res) => { + res.should.have.property('depth').equal(1); + res.should.have.property('nodesCount').equal(1); + res.should.have.property('leavesCount').equal(2); + res.should.have.property('root').equal('EA6180FE4B924AFC64D3EE7D42C2C58CC4AF244B'); + res.should.have.property('leaves').length(2); + res.leaves[0].should.equal('6F9D30999682338B713CEB3175C2406B5A438A65'); + res.leaves[1].should.equal('CB9F165229579D66447F4C5A0EABAD6F51985387'); + }); + }); + + it('/peers?leaf=6F9D30999682338B713CEB3175C2406B5A438A65', function() { + return expectAnswer(rp('http://127.0.0.1:20502/network/peering/peers?leaf=6F9D30999682338B713CEB3175C2406B5A438A65', { json: true }), (res) => { + res.should.have.property('depth').equal(1); + res.should.have.property('nodesCount').equal(1); + res.should.have.property('leavesCount').equal(2); + res.should.have.property('root').equal('EA6180FE4B924AFC64D3EE7D42C2C58CC4AF244B'); + res.should.have.property('leaves').length(0); + res.should.have.property('leaf').have.property('hash').equal('6F9D30999682338B713CEB3175C2406B5A438A65'); + res.should.have.property('leaf').have.property('value'); + res.should.have.property('leaf').have.property('value').have.property('pubkey').equal('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo'); + res.should.have.property('leaf').have.property('value').have.property('block').equal('0-DA39A3EE5E6B4B0D3255BFEF95601890AFD80709'); + res.should.have.property('leaf').have.property('value').have.property('signature').equal('bSWLDHDPUs7U8+tgVFcny5li3FBeTXeNhf7jkAeFBHG9B1SUWs75vPoHE4TUQVNyxfZ9vjx6U8lf8HAPxTcLAw=='); + res.should.have.property('leaf').have.property('value').have.property('status').equal('UP'); + res.should.have.property('leaf').have.property('value').have.property('currency').equal('bb'); + res.should.have.property('leaf').have.property('value').have.property('endpoints').length(1); + res.leaf.value.endpoints[0].should.equal('BASIC_MERKLED_API 127.0.0.1 20502'); + }); + }); + }); + + it('/peers?leaf=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', function() { + return expectHttpCode(404, rp('http://127.0.0.1:20502/network/peering/peers?leaf=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', { json: true })); + }); +}); diff --git a/test/integration/tools/node.js b/test/integration/tools/node.js index 734f8ddd21fdfa4f8d517cb0095cb2113157e7a7..ea56765ab5b69580d49c9d047e6558e1b2d2302c 100644 --- a/test/integration/tools/node.js +++ b/test/integration/tools/node.js @@ -274,11 +274,15 @@ function Node (dbName, options) { that.http.network.peering.get(done); }; + this.peeringP = () => Q.nfcall(this.peering); + this.submitPeer = function(peer, done) { post('/network/peering/peers', { "peer": Peer.statics.peerize(peer).getRawSigned() }, done); }; + this.submitPeerP = (peer) => Q.nfcall(this.submitPeer, peer); + this.commitP = () => Q.nfcall(this.commit()); }