updateCache2.ts 10.6 KB
Newer Older
1 2
"use strict";

3 4 5
import {DataFinder} from "./DataFinder";
import {DBBlock} from "duniter/app/lib/db/DBBlock";

6
const co = require('co');
7
const constants = require(__dirname + '/constants')
8

9 10 11 12
/**
     * updateCache
     * 
     */
13
module.exports = async (req:any, res:any, next:any) => {
14
  
Éloïs's avatar
Éloïs committed
15
  var { duniterServer, cache } = req.app.locals
16

17 18
	const dataFinder = new DataFinder(duniterServer)

19
  try {
Éloïs's avatar
Éloïs committed
20 21 22
		// Définition des constantes
		const conf = duniterServer.conf;
		
23
		// Définition des variables
Éloïs's avatar
Éloïs committed
24
		let upgradeCache = false;
25 26
		
		// Cacluler s'il faut mettre à jour le cache ou pas
Éloïs's avatar
Éloïs committed
27
		upgradeCache = (Math.floor(Date.now() / 1000) > (cache.lastUptime + constants.MIN_CACHE_UPDATE_FREQ));
28 29
		
		// Si le cache membersCount est dévérouillé, le vérouiller, sinon ne pas réinitialiser le cache
Éloïs's avatar
Éloïs committed
30
		if (upgradeCache && !cache.lockMembersCount)
31 32 33 34 35
		{
			cache.lockMembersCount = true;
		}
		else if(cache.lockMembersCount)
		{
Éloïs's avatar
Éloïs committed
36
			upgradeCache = false;
37
		}
Éloïs's avatar
Éloïs committed
38

39
    // If fork, unstack cache
Éloïs's avatar
Éloïs committed
40
    let reinitBdd = false;
41 42
    if (cache.endBlock != null)
    {
43
      let checkBlock = [await dataFinder.getBlock(cache.blockchain[cache.blockchain.length-1].number) as DBBlock];
Éloïs's avatar
Éloïs committed
44
			if (cache.blockchain.length > 0 && cache.blockchain[cache.blockchain.length-1].hash != checkBlock[0].hash && upgradeCache)
45
      {
Éloïs's avatar
Éloïs committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
				// reinitialize cache
				cache.lastUptime = 0;
				cache.lockMembersCount = false;
				cache.beginBlock = null;
				cache.currentBlockNumber = 0;
				cache.currentBlockTime = 0;
				cache.currentSentries = 0;
				cache.endBlock = null;
				cache.step = null;
				cache.stepUnit = null;
				cache.stepTime = null;
				cache.onlyDate = null;
				cache.Yn = 0;
				cache.pubkeys = new Array();
				cache.pub_index = new Array();
				cache.blockchain = new Array();
62
				
Éloïs's avatar
Éloïs committed
63 64
				// reinitialize bdd
				reinitBdd = true;
65 66 67 68 69 70 71 72 73 74 75 76 77
      }
    }
    
    // define step
    cache.step = 1;
    if (typeof(req.query.step) != 'undefined' && parseInt(req.query.step) > 0) { cache.step = req.query.step; }
    
    // calculate unitTime and onlyDate
    let unitTime = 0;
    if (typeof(req.query.stepUnit) != 'undefined')
    {
      switch (req.query.stepUnit)
      {
78
				case "blocks": unitTime = 300; cache.onlyDate = false; cache.stepUnit = "blocks"; break;
Éloïs's avatar
Éloïs committed
79 80 81 82 83
				case "hours": unitTime = 3600; cache.onlyDate = false; cache.stepUnit = "hours"; break;
				case "days": unitTime = 86400; cache.onlyDate = true; cache.stepUnit = "days"; break;
				case "weeks": unitTime = 604800; cache.onlyDate = true; cache.stepUnit = "weeks"; break;
				case "months": unitTime = 18144000; cache.onlyDate = true; cache.stepUnit = "months"; break;
				case "years": unitTime = 31557600; cache.onlyDate = true; cache.stepUnit = "years"; break;
84 85 86 87 88
      }
    }
    // Default values
    else
    {
Éloïs's avatar
Éloïs committed
89
      unitTime = 86400; cache.onlyDate = true; cache.stepUnit = "days";
90 91
    }
    
92
    // get endBlock
93
    if ( typeof(req.query.end) == 'undefined' || req.query.end <= 0)
94
    {
95
      cache.endBlock = [await dataFinder.getCurrentBlockOrNull()];
96 97 98
    }
    else
    {
99
      cache.endBlock = [await dataFinder.getBlock(req.query.end)];
100 101
      // Si end >= currentBlock, get currentBlock
      if ( typeof(cache.endBlock[0]) == 'undefined' )
102
      {
103
				cache.endBlock = [await dataFinder.getCurrentBlockOrNull()];
104
      }
105
		}
106 107 108
    
    // fix begin value
    if ( typeof(req.query.begin) == 'undefined' || req.query.begin < 0 )
109
    { cache.beginBlock = [await dataFinder.getBlock(0)]; }
110 111
    else if (req.query.begin > cache.endBlock[0].number)
    {
112
			let beginTime = cache.endBlock[0].medianTime-(parseInt(cache.step)*unitTime*constants.STEP_COUNT_MIN);
113
      cache.beginBlock =  [await dataFinder.getBlockWhereMedianTimeGte(beginTime)];
114
    }
115
		else { cache.beginBlock = [await dataFinder.getBlock(req.query.begin)]; }
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

		// Define nbMaxPoints and adaptMaxPoints
		if ( typeof(req.query.nbMaxPoints) != 'undefined' && req.query.nbMaxPoints > 0 ) {
			cache.nbMaxPoints = req.query.nbMaxPoints;
		} else {
			cache.nbMaxPoints = constants.STEP_COUNT_MAX;
		}
		if ( typeof(req.query.adaptMaxPoints) != 'undefined' && (req.query.adaptMaxPoints == "step" || req.query.adaptMaxPoints == "end")) {
			cache.adaptMaxPoints = req.query.adaptMaxPoints;
		} else {
			cache.adaptMaxPoints = "begin";
		}
		
		// Apply nbMaxPoints and adaptMaxPoints
		if (cache.adaptMaxPoints == "begin")
131
		{
132 133 134
			if ( Math.ceil((cache.endBlock[0].medianTime-cache.beginBlock[0].medianTime)/(cache.step*unitTime)) > cache.nbMaxPoints  )
			{
				let newBeginTime = cache.endBlock[0].medianTime-cache.step*cache.nbMaxPoints*unitTime;
135
				cache.beginBlock =  [await dataFinder.getBlockWhereMedianTimeGte(newBeginTime)];
136 137
			}
		} else if (cache.adaptMaxPoints == "step") {
138
			cache.step = Math.ceil((cache.endBlock[0].medianTime-cache.beginBlock[0].medianTime)/(constants.STEP_COUNT_MAX*unitTime));
139 140
		} else {
			let newEndTime = cache.beginBlock[0].medianTime+cache.step*cache.nbMaxPoints*unitTime;
141
			cache.endBlock = [await dataFinder.getBlockWhereMedianTimeLte(newEndTime)];
142
		}
143 144
    
		// Calculate stepTime
145
    cache.stepTime = parseInt(cache.step)*unitTime;
146

Éloïs's avatar
Éloïs committed
147
    // if new blocks and MIN_CACHE_UPDATE_FREQ pass, update cache
148
		if ( parseInt(cache.endBlock[0].number) >= cache.currentBlockNumber && Math.floor(Date.now() / 1000) > (cache.lastUptime + constants.MIN_CACHE_UPDATE_FREQ))
149
    {
Éloïs's avatar
Éloïs committed
150
      // let previousCacheTime = (cache.blockchain.length > 0) ? cache.blockchain[cache.blockchain.length-1].medianTime:0;
151
      var newBlocks = await dataFinder.getBlockWhereMedianTimeLteAndGtNoLimit(cache.currentBlockTime, cache.endBlock[0].medianTime);
152
      
Éloïs's avatar
Éloïs committed
153 154
      // Initialise newJoiners
      let newJoiners = new Array();
Éloïs's avatar
Éloïs committed
155
      
Éloïs's avatar
Éloïs committed
156 157
      // Initialise delIdtys
      let delIdtys = new Array();
Éloïs's avatar
Éloïs committed
158
      
159 160
      for (let b=0;b<newBlocks.length;b++)
      {
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
				// Init let variables
				let newSentries=0;
				let expireCertsNumber=-1;
				let minReceivedCerts = 0;
				let revoked = [];
				let actives = [];
				let joiners = [];
				let certifications = [];
				
				/*// get expireCertsNumber
				let tmpExpireCertsBlock = yield duniterServer.dal.peerDAL.query(
				'SELECT `number` FROM block WHERE `fork`=0 AND `medianTime` > '+cache.currentBlockTime+' AND `medianTime` < '+(parseInt(newBlocks[b].medianTime)-sigValidity)+' ORDER BY `medianTime` DESC LIMIT 1');
							if (tmpExpireCertsBlock.length > 0) { expireCertsNumber = parseInt(tmpExpireCertsBlock[0].number); }
							
							// Suppr expires certs
							if (expireCertsNumber >= 0)
				{
					for (let m=0;m<cache.pubkeys.length;m++)
					{
						//..
					}
				}*/
Éloïs's avatar
Éloïs committed
183 184
        
        // For become sentrie, minReceivedCerts is max between Yn and sigQty
185
				minReceivedCerts = (cache.Yn<conf.sigQty) ? conf.sigQty:cache.Yn;
Éloïs's avatar
Éloïs committed
186

187 188 189 190 191 192
				// If Yn change, suppr sentries that not achieve new Yn value
				let newYn = Math.ceil(Math.pow(newBlocks[b].membersCount, 1/conf.stepMax));
				if (newYn > cache.Yn && cache.Yn > 0)
				{
					for (let m=0;m<cache.pubkeys.length;m++)
					{
Éloïs's avatar
Éloïs committed
193
						if (cache.pubkeys[m].writtenCerts.length >= cache.Yn && cache.pubkeys[m].receivedCerts.length >= minReceivedCerts && (cache.pubkeys[m].writtenCerts.length < newYn || cache.pubkeys[m].receivedCerts.length < newYn)) { newSentries -= 1; }
194 195 196 197
					}
					minReceivedCerts = (newYn<conf.sigQty) ? conf.sigQty:newYn; // recalculate minReceivedCerts
				}
				cache.Yn = newYn;
Éloïs's avatar
Éloïs committed
198

199 200 201 202 203 204 205 206 207
				// parse and split revoked
				revoked = JSON.parse(newBlocks[b].revoked);
				for (let r=0;r<revoked.length;r++)
				{
					revoked[r] = revoked[r].split(":");
					delIdtys.push(revoked[r][0]);
					let tmpPubIndex = cache.pub_index[revoked[r][0]];
					//cache.pubkeys.splice(tmpPubIndex,1);
				}
Éloïs's avatar
Éloïs committed
208

209 210 211 212 213 214 215
				// parse and split actives
				actives = JSON.parse(newBlocks[b].actives);
				for (let a=0;a<actives.length;a++)
				{
					actives[a] = actives[a].split(":");
					cache.pubkeys[cache.pub_index[actives[a][0]]].expires_on = newBlocks[b].medianTime+conf.msValidity;
				}
Éloïs's avatar
Éloïs committed
216

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
				// parse and split joiners
				joiners = JSON.parse(newBlocks[b].joiners);
				for (let j=0;j<joiners.length;j++)
				{
					joiners[j] = joiners[j].split(":");
					if ( typeof(cache.pub_index[joiners[j][0]]) != 'undefined') 
					{
						let tmpPubkeyIndex = cache.pub_index[joiners[j][0]];
						cache.pubkeys[tmpPubkeyIndex].updateWot = true;
						cache.pubkeys[tmpPubkeyIndex].expires_on = newBlocks[b].medianTime+conf.msValidity;
					}
					else
					{
						cache.pubkeys.push({
							updateWot: false,
							expires_on: newBlocks[b].medianTime+conf.msValidity,
							pub: joiners[j][0],
							writtenCerts: new Array(),
							receivedCerts: new Array()       
						});
						cache.pub_index[joiners[j][0]] = cache.pubkeys.length-1;
						newJoiners.push(joiners[j][0]);
					}
				}
Éloïs's avatar
Éloïs committed
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
				// parse and split certifications
				certifications = JSON.parse(newBlocks[b].certifications);
				for (let c=0;c<certifications.length;c++)
				{
					certifications[c] = certifications[c].split(":");
					// push cert to cache
					cache.pubkeys[cache.pub_index[certifications[c][0]]].writtenCerts.push(certifications[c][2]);
					cache.pubkeys[cache.pub_index[certifications[c][0]]].updateWot = true;
					cache.pubkeys[cache.pub_index[certifications[c][1]]].receivedCerts.push(certifications[c][2]);
					cache.pubkeys[cache.pub_index[certifications[c][1]]].updateWot = true;
					
					// Calculate if the issuer of cert become sentry
					if (cache.pubkeys[cache.pub_index[certifications[c][0]]].writtenCerts.length == cache.Yn && cache.pubkeys[cache.pub_index[certifications[c][0]]].receivedCerts.length >= minReceivedCerts)
					{ newSentries++; }
					
					// Calculate if the receiver of cert become sentry
					if (cache.pubkeys[cache.pub_index[certifications[c][1]]].writtenCerts.length >= cache.Yn && cache.pubkeys[cache.pub_index[certifications[c][1]]].receivedCerts.length == minReceivedCerts)
					{ newSentries++; }
				}
Éloïs's avatar
Éloïs committed
261

262 263 264 265 266 267 268 269 270 271
				if (newSentries != 0)
				{
					cache.blockchain.push({
						number: newBlocks[b].number,
						hash: newBlocks[b].hash,
						medianTime: newBlocks[b].medianTime,
						newSentries: newSentries,
						sentries: (cache.blockchain.length > 0) ? cache.blockchain[cache.blockchain.length-1].sentries+newSentries:newSentries
					});
				}
Éloïs's avatar
Éloïs committed
272
      } // end of newBlocks loop
273

Éloïs's avatar
Éloïs committed
274 275 276
      // update cache.currentBlockNumber and cache.currentBlockTime
      cache.currentBlockNumber = cache.endBlock[0].number;
      cache.currentBlockTime = cache.endBlock[0].medianTime;
Éloïs's avatar
Éloïs committed
277
      
Éloïs's avatar
Éloïs committed
278 279
      // Upgrade lastUptime
      cache.lastUptime = Math.floor(Date.now() / 1000);
280
    }
Éloïs's avatar
Éloïs committed
281

282
      // Unlock Members count cache
Éloïs's avatar
Éloïs committed
283
      if (upgradeCache)
284 285 286
			{
        cache.lockMembersCount = false;
			}
Éloïs's avatar
Éloïs committed
287

288 289
    next()
  } catch (e) {
290
		console.error(e.stack || e)
291 292 293
    // En cas d'exception, afficher le message
    res.status(500).send(`<pre>${e.stack || e.message}</pre>`)
  }
294 295
}