From 3500e84911cd51bb1b4fff878885f26b7aed6f3c Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Sat, 9 Jan 2016 17:42:03 +0100
Subject: [PATCH] Fix: merkle URI for peers was broken

---
 app/controllers/network.js     |   6 +-
 app/lib/constants.js           |   3 +-
 app/lib/streams/bma.js         |   2 +-
 app/lib/streams/dtos.js        |   4 +-
 app/service/MerkleService.js   |   1 +
 test/integration/network.js    | 142 +++++++++++++++++++++++++++++++++
 test/integration/tools/node.js |   4 +
 7 files changed, 157 insertions(+), 5 deletions(-)
 create mode 100644 test/integration/network.js

diff --git a/app/controllers/network.js b/app/controllers/network.js
index 326782f24..b8e84ac75 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 07408574b..562e5a411 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 0835e476e..2a35d73b6 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 0a5fcbb58..a69a5a166 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 296f19612..6dba78727 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/test/integration/network.js b/test/integration/network.js
new file mode 100644
index 000000000..6a7e1f7d7
--- /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 734f8ddd2..ea56765ab 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());
 }
-- 
GitLab