itns-sidechain/lib/protocol/timedata.js

149 lines
2.8 KiB
JavaScript
Raw Normal View History

2016-04-19 05:47:47 -07:00
/*!
2017-07-20 13:13:47 -07:00
* timedata.js - time management for bcoin
2016-04-19 05:47:47 -07:00
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
2017-02-03 22:47:26 -08:00
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
2016-06-09 16:18:50 -07:00
* https://github.com/bcoin-org/bcoin
2016-04-19 05:47:47 -07:00
*/
2016-06-13 01:06:01 -07:00
'use strict';
const EventEmitter = require('events');
2017-07-20 01:09:52 -07:00
const util = require('../utils/util');
2017-10-26 04:07:36 -07:00
const binary = require('../utils/binary');
2016-04-19 05:47:47 -07:00
/**
2017-11-16 19:46:19 -08:00
* Time Data
2016-04-19 05:47:47 -07:00
* An object which handles "adjusted time". This may not
* look it, but this is actually a semi-consensus-critical
* piece of code. It handles version packets from peers
* and calculates what to offset our system clock's time by.
2017-02-03 22:47:26 -08:00
* @alias module:protocol.TimeData
2017-11-16 19:46:19 -08:00
* @extends EventEmitter
2016-04-19 05:47:47 -07:00
* @property {Array} samples
* @property {Object} known
2016-04-19 05:49:05 -07:00
* @property {Number} limit
2016-04-19 05:53:06 -07:00
* @property {Number} offset
2016-04-19 05:47:47 -07:00
*/
2017-11-16 19:46:19 -08:00
class TimeData extends EventEmitter {
/**
* Create time data.
* @constructor
* @param {Number} [limit=200]
*/
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
constructor(limit) {
super();
2016-07-04 05:36:06 -07:00
2017-11-16 19:46:19 -08:00
if (limit == null)
limit = 200;
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
this.samples = [];
this.known = new Map();
this.limit = limit;
this.offset = 0;
this.checked = false;
}
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
/**
* Add time data.
* @param {String} id
* @param {Number} time
*/
2016-07-04 05:36:06 -07:00
2017-11-16 19:46:19 -08:00
add(id, time) {
if (this.samples.length >= this.limit)
return;
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
if (this.known.has(id))
return;
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
const sample = time - util.now();
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
this.known.set(id, sample);
2017-11-16 19:46:19 -08:00
binary.insert(this.samples, sample, compare);
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
this.emit('sample', sample, this.samples.length);
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
if (this.samples.length >= 5 && this.samples.length % 2 === 1) {
let median = this.samples[this.samples.length >>> 1];
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
if (Math.abs(median) >= 70 * 60) {
if (!this.checked) {
let match = false;
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
for (const offset of this.samples) {
if (offset !== 0 && Math.abs(offset) < 5 * 60) {
match = true;
break;
}
}
2017-08-10 12:32:49 -07:00
2017-11-16 19:46:19 -08:00
if (!match) {
this.checked = true;
this.emit('mismatch');
2016-04-19 05:47:47 -07:00
}
2016-05-05 17:47:29 -07:00
}
2017-08-10 12:32:49 -07:00
2017-11-16 19:46:19 -08:00
median = 0;
2016-04-19 05:47:47 -07:00
}
2017-08-10 12:32:49 -07:00
2017-11-16 19:46:19 -08:00
this.offset = median;
this.emit('offset', this.offset);
2016-04-19 05:47:47 -07:00
}
}
2017-11-16 19:46:19 -08:00
/**
* Get the current adjusted time.
* @returns {Number} Adjusted Time.
*/
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
now() {
return util.now() + this.offset;
}
2016-04-19 05:47:47 -07:00
2017-11-16 19:46:19 -08:00
/**
* Adjust a timestamp.
* @param {Number} time
* @returns {Number} Adjusted Time.
*/
2017-11-16 19:46:19 -08:00
adjust(time) {
return time + this.offset;
}
2017-11-16 19:46:19 -08:00
/**
* Unadjust a timestamp.
* @param {Number} time
* @returns {Number} Local Time.
*/
2017-11-16 19:46:19 -08:00
local(time) {
return time - this.offset;
}
2017-11-16 19:46:19 -08:00
/**
* Get the current adjusted time in milliseconds.
* @returns {Number} Adjusted Time.
*/
2017-03-06 18:25:06 -08:00
2017-11-16 19:46:19 -08:00
ms() {
return Date.now() + this.offset * 1000;
}
}
2017-03-06 18:25:06 -08:00
2016-05-15 18:07:06 -07:00
/*
* Helpers
*/
2016-04-19 05:47:47 -07:00
function compare(a, b) {
return a - b;
}
2016-05-15 18:07:06 -07:00
/*
* Expose
*/
2016-11-28 16:52:30 -08:00
module.exports = TimeData;