UNPKG

js-oip

Version:

A Javascript Library to fully interact with the Open Index Protocol

196 lines (142 loc) 6.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; require("core-js/modules/es6.regexp.to-string"); var _fcoin = require("fcoin"); var _blgr = _interopRequireDefault(require("blgr")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const NetAddress = _fcoin.net.NetAddress, packets = _fcoin.net.packets; /* Create a Flo p2p Peer */ class Peer { /** * Initialize the Peer * @param {Object} settings * @param {Object} settings.ip - The IP address of the Flo Peer to connect to * @param {Object} [settings.agent="js-oip fcoin Peer"] - The "name" to display to nodes you connect to. * @return {Peer} */ constructor(settings) { // Store our internally settings for later use this.settings = settings; // Rename the mainnet network to be what fcoin expects if (this.settings.network === 'mainnet' || this.settings.network === 'livenet') { this.settings.network = 'main'; } // Set the initial connection status this.connected = false; // Initialize the transaction map to store { 'txid': 'hex' } the txid related to the hex this.txMap = {}; // Initialize a logging limiter variable this.singleLog = 0; } /** * Open a p2p connection to the Peer * @return {Boolean} Returns the connection status */ async connect() { let log = new _blgr.default({ level: 'spam' }); // Open up the logger await log.open(); // Create the Fcoin Peer this.peer = _fcoin.Peer.fromOptions({ logger: log, network: this.settings.network, agent: this.settings.agent }); // Create a NetAddress from our passed in IP address:port let address = NetAddress.fromHostname(this.settings.ip); // Fire off the initial connection attempt this.peer.connect(address); // When we recieve packets from peers, process them using the onPacket function this.peer.parser.on('packet', this.onPacket.bind(this)); // Handle/log errors this.peer.parser.on('error', e => { console.error(e); }); this.peer.on('error', e => { console.error(e); }); try { // Wait for the peer to open up await this.peer.open(); // Set connected to true once we have connected this.connected = true; } catch (e) { // Handle connection error and set connected explicitly to false this.connected = false; } // Return the final connection status return this.connected; } /** * Announce the availability of a Transaction to the Peer * @param {Array.<String>} hex - The hex string of the transaction */ announceTXs(hexArray) { // First, check if we are connected before attempting to broadcast out if (this.connected) { try { let txArray = []; for (let hex of hexArray) { // Create an `fcoin` transaction from our tx hex let mytx = new _fcoin.TX().fromRaw(Buffer.from(hex, 'hex')); // Store the hash of the transaction in our txMap this.txMap[mytx.hash('hex')] = hex; // Add it to our array to announce txArray.push(mytx); } // Announce the Transactions to the peer this.peer.announceTX(txArray); this.peer.flushInv(); } catch (e) { // Throw an error if one happened console.error('Announce TXs Error: ' + e); } } } /** * Handle incoming p2p packets * @param {Packet} packet - The packet that is incoming */ onPacket(packet) { // Check which packet type is incoming switch (packet.type) { // If the packet is `GETDATA` that means they are requesting us to send them tne transaction case packets.types.GETDATA: // Send the transaction to the peer this.handleGetData(packet); break; } } /** * Handle (respond to) a p2p getdata request * @param {GetDataPacket} getDataPacket - The packet to respond to with data */ handleGetData(getDataPacket) { // Track the total number of transactions relayed let txsRelayed = 0; // Track the last txid hash that we sent let lastHash; // If the peer is requesting more than one transaction, or if they have not met the singlelog maximum, then log the request if (getDataPacket.items.length > 1 || this.singleLog < 5) { console.log(`[RPC Wallet] Peer ${this.settings.ip} requested ${getDataPacket.items.length} items...`); } // Loop through each requested item in the getData packet for (let item of getDataPacket.items) { // We only care about responding if they are requesting a transction let regTX = item.type === _fcoin.InvItem.types.TX; let segTX = item.type === _fcoin.InvItem.types.WITNESS_TX; // If we are a regular tx, or a segwit tx, then continue if (regTX || segTX) { // Check to see if we have this transction in our txMap, and if not, skip it (ignore transactions that are not our own) if (!this.txMap[item.hash.toString('hex')]) { console.error(`Item Peer requested is NOT in our txMap`); continue; } // Create an `fcoin` tx from the cached tx hex let mytx = new _fcoin.TX().fromRaw(Buffer.from(this.txMap[item.hash.toString('hex')], 'hex')); // Include the transaction in a TXPacket to be sent to the Peer let txPacket = new packets.TXPacket(mytx, segTX); // Send out the TXPacket to the Peer this.peer.send(txPacket); // Increase our count of transactions relayed txsRelayed++; // Store the previous hash (for logging purposes) lastHash = mytx.rhash(); } } // If we have responded to at least one getdata item, then log our response if (txsRelayed > 0) { // If we have logged a single tx being relayed more than 5 times, then just skip logging (to prevent spam) if (txsRelayed === 1 && this.singleLog > 5) { return; } // If we only relayed a single transaction, then increase the "singleLog" counter if (txsRelayed === 1) { this.singleLog++; } } // Log information about the sent transactions console.log(`[RPC Wallet] Relayed ${txsRelayed}/${getDataPacket.items.length} requested transactions to ${this.settings.ip} (last txid ${lastHash})`); } } var _default = Peer; exports.default = _default;