UNPKG

hsd

Version:
148 lines (115 loc) 2.79 kB
/*! * timedata.js - time management for hsd * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License). * https://github.com/handshake-org/hsd */ 'use strict'; const EventEmitter = require('events'); const util = require('../utils/util'); const binary = require('../utils/binary'); /** * Time Data * 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. * @alias module:protocol.TimeData * @extends EventEmitter * @property {Array} samples * @property {Object} known * @property {Number} limit * @property {Number} offset */ class TimeData extends EventEmitter { /** * Create time data. * @constructor * @param {Number} [limit=200] */ constructor(limit) { super(); if (limit == null) limit = 200; this.samples = []; this.known = new Map(); this.limit = limit; this.offset = 0; this.checked = false; } /** * Add time data. * @param {String} id * @param {Number} time */ add(id, time) { if (this.samples.length >= this.limit) return; if (this.known.has(id)) return; const sample = time - util.now(); this.known.set(id, sample); binary.insert(this.samples, sample, compare); this.emit('sample', sample, this.samples.length); if (this.samples.length >= 5 && this.samples.length % 2 === 1) { let median = this.samples[this.samples.length >>> 1]; if (Math.abs(median) >= 70 * 60) { if (!this.checked) { let match = false; for (const offset of this.samples) { if (offset !== 0 && Math.abs(offset) < 5 * 60) { match = true; break; } } if (!match) { this.checked = true; this.emit('mismatch'); } } median = 0; } this.offset = median; this.emit('offset', this.offset); } } /** * Get the current adjusted time. * @returns {Number} Adjusted Time. */ now() { return util.now() + this.offset; } /** * Adjust a timestamp. * @param {Number} time * @returns {Number} Adjusted Time. */ adjust(time) { return time + this.offset; } /** * Unadjust a timestamp. * @param {Number} time * @returns {Number} Local Time. */ local(time) { return time - this.offset; } /** * Get the current adjusted time in milliseconds. * @returns {Number} Adjusted Time. */ ms() { return Date.now() + this.offset * 1000; } } /* * Helpers */ function compare(a, b) { return a - b; } /* * Expose */ module.exports = TimeData;