UNPKG

hsd

Version:
423 lines (334 loc) 9.03 kB
/*! * network.js - network object for hsd * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License). * https://github.com/handshake-org/hsd */ 'use strict'; const assert = require('bsert'); const binary = require('../utils/binary'); const networks = require('./networks'); const TimeData = require('./timedata'); /** @typedef {import('../types').NetworkType} NetworkType */ /** * Network * Represents a network. * @alias module:protocol.Network */ class Network { /** * Create a network. * @constructor * @param {Object} options */ constructor(options) { assert(!Network[options.type], 'Cannot create two networks.'); this.type = options.type; this.seeds = options.seeds; this.magic = options.magic; this.port = options.port; this.brontidePort = options.brontidePort; this.checkpointMap = options.checkpointMap; this.lastCheckpoint = options.lastCheckpoint; this.checkpoints = []; this.halvingInterval = options.halvingInterval; this.coinbaseMaturity = options.coinbaseMaturity; this.genesis = options.genesis; this.genesisBlock = options.genesisBlock; this.pow = options.pow; this.names = options.names; this.goosigStop = options.goosigStop; this.block = options.block; this.activationThreshold = options.activationThreshold; this.minerWindow = options.minerWindow; this.deployments = options.deployments; this.deploys = options.deploys; this.unknownBits = 0; this.keyPrefix = options.keyPrefix; this.addressPrefix = options.addressPrefix; this.requireStandard = options.requireStandard; this.rpcPort = options.rpcPort; this.walletPort = options.walletPort; this.nsPort = options.nsPort; this.rsPort = options.rsPort; this.minRelay = options.minRelay; this.feeRate = options.feeRate; this.maxFeeRate = options.maxFeeRate; this.identityKey = options.identityKey; this.selfConnect = options.selfConnect; this.requestMempool = options.requestMempool; this.claimPrefix = options.claimPrefix; this.deflationHeight = options.deflationHeight; this.time = new TimeData(); this.txStart = options.txStart; this.init(); } /** * Get a deployment by bit index. */ init() { let bits = 0; for (const deployment of this.deploys) bits |= 1 << deployment.bit; this.unknownBits = ~bits >>> 0; for (const key of Object.keys(this.checkpointMap)) { const hash = this.checkpointMap[key]; const height = Number(key); this.checkpoints.push({ hash, height }); } this.checkpoints.sort(cmpNode); } /** * Get a deployment by bit index. * @param {Number} bit * @returns {Object} */ byBit(bit) { const index = binary.search(this.deploys, bit, cmpBit); if (index === -1) return null; return this.deploys[index]; } /** * Get network adjusted time. * @returns {Number} */ now() { return this.time.now(); } /** * Get network adjusted time in milliseconds. * @returns {Number} */ ms() { return this.time.ms(); } /** * Create a network. Get existing network if possible. * @param {NetworkType|Object} options * @returns {Network} */ static create(options) { if (typeof options === 'string') options = networks[options]; assert(options, 'Unknown network.'); if (Network[options.type]) return Network[options.type]; const network = new Network(options); Network[network.type] = network; if (!Network.primary) Network.primary = network; return network; } /** * Set the default network. This network will be used * if nothing is passed as the `network` option for * certain objects. * @param {NetworkType} type - Network type. * @returns {Network} */ static set(type) { assert(typeof type === 'string', 'Bad network.'); Network.primary = Network.get(type); Network.type = type; return Network.primary; } /** * Get a network with a string or a Network object. * @param {NetworkType|Network} type - Network type. * @returns {Network} */ static get(type) { if (!type) { assert(Network.primary, 'No default network.'); return Network.primary; } if (type instanceof Network) return type; if (typeof type === 'string') return Network.create(type); throw new Error('Unknown network.'); } /** * Get a network with a string or a Network object. * @param {NetworkType|Network} type - Network type. * @returns {Network} */ static ensure(type) { if (!type) { assert(Network.primary, 'No default network.'); return Network.primary; } if (type instanceof Network) return type; if (typeof type === 'string') { if (networks[type]) return Network.create(type); } assert(Network.primary, 'No default network.'); return Network.primary; } /** * Get a network by an associated comparator. * @private * @param {Object} value * @param {Function} compare * @param {(NetworkType|Network)?} network * @param {String} name * @returns {Network} */ static by(value, compare, network, name) { if (network) { network = Network.get(network); if (compare(network, value)) return network; throw new Error(`Network mismatch for ${name}.`); } for (const type of networks.types) { network = networks[type]; if (compare(network, value)) return Network.get(type); } throw new Error(`Network not found for ${name}.`); } /** * Get a network by its magic number. * @param {Number} value * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromMagic(value, network) { return Network.by(value, cmpMagic, network, 'magic number'); } /** * Get a network by its WIF prefix. * @param {Number} prefix * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromWIF(prefix, network) { return Network.by(prefix, cmpWIF, network, 'WIF'); } /** * Get a network by its xpubkey prefix. * @param {Number} prefix * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromPublic(prefix, network) { return Network.by(prefix, cmpPub, network, 'xpubkey'); } /** * Get a network by its xprivkey prefix. * @param {Number} prefix * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromPrivate(prefix, network) { return Network.by(prefix, cmpPriv, network, 'xprivkey'); } /** * Get a network by its xpubkey base58 prefix. * @param {String} prefix * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromPublic58(prefix, network) { return Network.by(prefix, cmpPub58, network, 'xpubkey'); } /** * Get a network by its xprivkey base58 prefix. * @param {String} prefix * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromPrivate58(prefix, network) { return Network.by(prefix, cmpPriv58, network, 'xprivkey'); } /** * Get a network by its bech32 address prefix. * @param {String} hrp * @param {(Network|NetworkType)?} [network] * @returns {Network} */ static fromAddress(hrp, network) { return Network.by(hrp, cmpAddress, network, 'address'); } /** * Convert the network to a string. * @returns {String} */ toString() { return this.type; } /** * Inspect the network. * @returns {String} */ inspect() { return `<Network: ${this.type}>`; } /** * Test an object to see if it is a Network. * @param {Object} obj * @returns {Boolean} */ static isNetwork(obj) { return obj instanceof Network; } } /** * Default network. * @type {Network} */ Network.primary = null; /** * Default network type. * @type {String} */ Network.type = null; /* * Networks (to avoid hash table mode). */ Network.main = null; Network.testnet = null; Network.regtest = null; Network.simnet = null; /* * Set initial network. */ // @ts-ignore Network.set(process.env.HSD_NETWORK || 'main'); /* * Helpers */ function cmpBit(a, b) { return a.bit - b; } function cmpNode(a, b) { return a.height - b.height; } function cmpMagic(network, magic) { return network.magic === magic; } function cmpWIF(network, prefix) { return network.keyPrefix.privkey === prefix; } function cmpPub(network, prefix) { return network.keyPrefix.xpubkey === prefix; } function cmpPriv(network, prefix) { return network.keyPrefix.xprivkey === prefix; } function cmpPub58(network, prefix) { return network.keyPrefix.xpubkey58 === prefix; } function cmpPriv58(network, prefix) { return network.keyPrefix.xprivkey58 === prefix; } function cmpAddress(network, hrp) { return network.addressPrefix === hrp; } /* * Expose */ module.exports = Network;