From 5f5eb2be81a125fd60b14638fb2dc54b492fc220 Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Thu, 9 Oct 2014 01:06:17 +0200
Subject: [PATCH] Certifications from WoT to WoT are also integrated within new
 blocks

---
 app/models/certification.js      | 12 +++++-
 app/models/identity.js           |  7 ++++
 app/service/BlockchainService.js | 71 +++++++++++++++++++++-----------
 app/service/IdentityService.js   |  6 +--
 4 files changed, 68 insertions(+), 28 deletions(-)

diff --git a/app/models/certification.js b/app/models/certification.js
index 6f618ecdf..0bda45725 100644
--- a/app/models/certification.js
+++ b/app/models/certification.js
@@ -15,6 +15,7 @@ var CertificationSchema = new Schema({
   time: { type: Date, default: Date.now },
   target: String,
   to: String,
+  linked: { type: Boolean, default: false },
   created: { type: Date, default: Date.now },
   updated: { type: Date, default: Date.now }
 });
@@ -34,9 +35,9 @@ CertificationSchema.virtual('when').get(function () {
 
 CertificationSchema.methods = {
 
-  exists: function (done) {
+  existing: function (done) {
     this.model('Certification').find({ "pubkey": this.pubkey, "sig": this.sig, "time": this.time, "target": this.target }, function (err, certs) {
-      done(err, certs && certs.length > 0);
+      done(err, certs && certs.length > 0 ? certs[0] : null);
     });
   },
 
@@ -77,4 +78,11 @@ CertificationSchema.statics.from = function (pubkey, done) {
   });
 };
 
+CertificationSchema.statics.findNew = function (done) {
+  var Certification = this.model('Certification');
+  Certification.find({ "linked": false }, function (err, certs) {
+    done(err, certs);
+  });
+};
+
 module.exports = CertificationSchema;
diff --git a/app/models/identity.js b/app/models/identity.js
index b3497f7fd..ecab6b5c8 100644
--- a/app/models/identity.js
+++ b/app/models/identity.js
@@ -144,6 +144,13 @@ IdentitySchema.statics.isMember = function(pubkey, done){
   });
 }
 
+IdentitySchema.statics.isMemberOrError = function(pubkey, done){
+  var Identity = this.model('Identity');
+  Identity.isMember(pubkey, function (err, isMember) {
+    done(err || (!isMember && "Not a member"));
+  });
+}
+
 IdentitySchema.statics.getMember = function(pubkey, done){
   var Identity = this.model('Identity');
   Identity.find({ "pubkey": pubkey, "member": true }, function (err, identities) {
diff --git a/app/service/BlockchainService.js b/app/service/BlockchainService.js
index 54ff51121..f9c1e95dc 100644
--- a/app/service/BlockchainService.js
+++ b/app/service/BlockchainService.js
@@ -317,16 +317,16 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
         },
         function (idty, next){
           cert.target = idty.getTargetHash();
-          cert.exists(next);
+          cert.existing(next);
         },
-        function (exists, next) {
-          if (exists) {
-            next();
-          } else {
-            cert.save(function (err) {
-              next(err);
-            });
+        function (existing, next) {
+          if (existing) {
+            cert = existing;
           }
+          cert.linked = true;
+          cert.save(function (err) {
+            next(err);
+          });
         }
       ], callback);
     }, done);
@@ -508,23 +508,49 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
       function (next){
         findUpdates(next);
       },
-      function (updates, subupdates, next){
+      function (updates, next){
         Block.current(function (err, current) {
-          next(null, current || null, updates, subupdates);
+          next(null, current || null, updates);
         });
       },
-      function (current, updates, subupdates, next){
-        createNewcomerBlock(current, null, {}, updates, subupdates, next);
+      function (current, updates, next){
+        createNewcomerBlock(current, null, {}, updates, next);
       },
     ], done);
   }
 
   function findUpdates (done) {
     var updates = {};
-    var subupdates = {};
     done(null, [], []);
     // TODO: certifications
-    // updates[pubkey] = certifications;
+    async.waterfall([
+      function (next){
+        Certification.findNew(next);
+      },
+      function (certs, next){
+        async.forEachSeries(certs, function(cert, callback){
+          async.waterfall([
+            function (next){
+              // Signatory must be a member
+              Identity.isMemberOrError(cert.from, next);
+            },
+            function (next){
+              // Certified must be a member
+              Identity.isMemberOrError(cert.to, next);
+            },
+            function (next){
+              updates[cert.to] = updates[cert.to] || [];
+              updates[cert.to].push(cert);
+              next();
+            },
+          ], function (err) {
+            callback();
+          });
+        }, next);
+      },
+    ], function (err) {
+      done(err, updates);
+    });
   }
 
   /**
@@ -605,7 +631,9 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
   * Generate a "newcomers" keyblock
   */
   this.generateNewcomersBlock = function (filteringFunc, checkingWoTFunc, done) {
-    var withoutUpdates = function(updates) { updates(null, {}, {}); };
+    var withoutUpdates = function(updatesDone) {
+      updatesDone(null, {});
+    };
     KeychainService.generateNextBlock(withoutUpdates, filteringFunc, checkingWoTFunc, done);
   };
 
@@ -614,7 +642,6 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
   */
   this.generateNextBlock = function (findUpdateFunc, filteringFunc, checkingWoTFunc, done) {
     var updates = {};
-    var subupdates = {};
     async.waterfall([
       function (next) {
         // First, check for members' key updates
@@ -622,7 +649,6 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
       },
       function (theUpdates, theSubupdates, next) {
         updates = theUpdates;
-        subupdates = theSubupdates;
         findNewcomers(filteringFunc, checkingWoTFunc, next);
       },
       function (current, newWoT, joinData, otherUpdates, next){
@@ -631,10 +657,10 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
           if (!updates[fpr])
             updates[fpr] = otherUpdates[fpr];
           else
-            updates[fpr].concat(otherUpdates[fpr]);
+            updates[fpr] = updates[fpr].concat(otherUpdates[fpr]);
         });
         // Create the block
-        createNewcomerBlock(current, joinData, updates, subupdates, next);
+        createNewcomerBlock(current, joinData, updates, next);
       },
     ], done);
   };
@@ -805,7 +831,6 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
   }
 
   function findSignaturesFromNewcomerToWoT (newcomer, done) {
-
     var updates = {};
     async.waterfall([
       function (next){
@@ -844,7 +869,7 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
     return matched;
   }
 
-  function createNewcomerBlock (current, joinData, updates, subupdates, done) {
+  function createNewcomerBlock (current, joinData, updates, done) {
     var block = new Block();
     block.version = 1;
     block.currency = current ? current.currency : conf.currency;
@@ -880,7 +905,7 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
     block.leavers = [];
     // Kicked people
     block.excluded = [];
-    // Certifications FROM the WoT
+    // Certifications from the WoT, to newcomers
     block.certifications = [];
     joiners.forEach(function(joiner){
       var data = joinData[joiner];
@@ -888,7 +913,7 @@ function BlockchainService (conn, conf, IdentityService, PeeringService) {
         block.certifications.push(cert.inline());
       });
     });
-    // Certifications TO the WoT
+    // Certifications from the WoT, to the WoT
     _(updates).keys().forEach(function(certifiedMember){
       var certs = updates[certifiedMember];
       certs.forEach(function(cert){
diff --git a/app/service/IdentityService.js b/app/service/IdentityService.js
index 7a44c2274..f50efdcb3 100644
--- a/app/service/IdentityService.js
+++ b/app/service/IdentityService.js
@@ -54,10 +54,10 @@ function IdentityService (conn, conf) {
             var mCert = new Certification({ pubkey: cert.from, sig: cert.sig, time: cert.time, target: obj.hash, to: idty.pubkey });
             async.waterfall([
               function (next){
-                mCert.exists(next);
+                mCert.existing(next);
               },
-              function (exists, next){
-                if (exists) next();
+              function (existing, next){
+                if (existing) next();
                 else mCert.save(function (err) {
                   next(err);
                 });
-- 
GitLab