UNPKG

turtlecoin-wallet-backend

Version:

[![Build Status](https://travis-ci.org/turtlecoin/turtlecoin-wallet-backend-js.svg?branch=master)](https://travis-ci.org/turtlecoin/turtlecoin-wallet-backend-js)

266 lines (265 loc) 10.5 kB
"use strict"; // Copyright (c) 2018, Zpalmtree // // Please see the included LICENSE file for more information. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const _ = require("lodash"); const events_1 = require("events"); const Config_1 = require("./Config"); const Logger_1 = require("./Logger"); const Types_1 = require("./Types"); const ValidateParameters_1 = require("./ValidateParameters"); const WalletError_1 = require("./WalletError"); const Assert_1 = require("./Assert"); /* REEEEE ADD TYPES */ const TurtleCoind = require('turtlecoin-rpc').TurtleCoind; /** * @deprecated This Class will be removed in v4.0.0. Please update your code * to instead use the [[Daemon]] class. This supports both ConventionalDaemon's, * BlockchainCacheApi's, and http/https, all automatically. */ class ConventionalDaemon extends events_1.EventEmitter { constructor(daemonHost, daemonPort) { super(); /** * The address node fees will go to */ this.feeAddress = ''; /** * The amount of the node fee in atomic units */ this.feeAmount = 0; /** * The amount of blocks the daemon we're connected to has */ this.localDaemonBlockCount = 0; /** * The amount of blocks the network has */ this.networkBlockCount = 0; /** * The amount of peers we have, incoming+outgoing */ this.peerCount = 0; /** * The hashrate of the last known local block */ this.lastKnownHashrate = 0; this.config = new Config_1.Config(); console.warn('This Class will be removed in v4.0.0. Please update your code ' + 'to instead use the Daemon class. This supports both ' + 'ConventionalDaemon\'s, BlockchainCacheApi\'s, and http/https, ' + 'all automatically.'); Assert_1.assertString(daemonHost, 'daemonHost'); Assert_1.assertNumber(daemonPort, 'daemonPort'); this.daemonHost = daemonHost; this.daemonPort = daemonPort; this.daemon = new TurtleCoind({ host: daemonHost, port: daemonPort, ssl: false, timeout: this.config.requestTimeout, }); } updateConfig(config) { this.config = Config_1.MergeConfig(config); } /** * Get the amount of blocks the network has */ getNetworkBlockCount() { return this.networkBlockCount; } /** * Get the amount of blocks the daemon we're connected to has */ getLocalDaemonBlockCount() { return this.localDaemonBlockCount; } /** * Initialize the daemon and the fee info */ init() { return __awaiter(this, void 0, void 0, function* () { /* Note - if one promise throws, the other will be cancelled */ yield Promise.all([this.updateDaemonInfo(), this.updateFeeInfo()]); }); } /** * Update the daemon info */ updateDaemonInfo() { return __awaiter(this, void 0, void 0, function* () { let info; try { info = yield this.daemon.info(); } catch (err) { Logger_1.logger.log('Failed to update daemon info: ' + err.toString(), Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]); return; } this.localDaemonBlockCount = info.height; this.networkBlockCount = info.network_height; /* Height returned is one more than the current height - but we don't want to overflow is the height returned is zero */ if (this.networkBlockCount !== 0) { this.networkBlockCount--; } this.peerCount = info.incoming_connections_count + info.outgoing_connections_count; this.lastKnownHashrate = info.difficulty / this.config.blockTargetTime; }); } /** * Get the node fee and address */ nodeFee() { return [this.feeAddress, this.feeAmount]; } /** * @param blockHashCheckpoints Hashes of the last known blocks. Later * blocks (higher block height) should be * ordered at the front of the array. * * @param startHeight Height to start taking blocks from * @param startTimestamp Block timestamp to start taking blocks from * * Gets blocks from the daemon. Blocks are returned starting from the last * known block hash (if higher than the startHeight/startTimestamp) */ getWalletSyncData(blockHashCheckpoints, startHeight, startTimestamp, blockCount) { return __awaiter(this, void 0, void 0, function* () { const { items, topBlock } = yield this.daemon.getWalletSyncData({ blockCount, blockHashCheckpoints, skipCoinbaseTransactions: !this.config.scanCoinbaseTransactions, startHeight, startTimestamp, }); return [items.map(Types_1.Block.fromJSON), topBlock]; }); } /** * @returns Returns a mapping of transaction hashes to global indexes * * Get global indexes for the transactions in the range * [startHeight, endHeight] */ getGlobalIndexesForRange(startHeight, endHeight) { return __awaiter(this, void 0, void 0, function* () { const data = yield this.daemon.getGlobalIndexesForRange({ endHeight, startHeight, }); const indexes = new Map(); for (const index of data) { indexes.set(index.key, index.value); } return indexes; }); } getCancelledTransactions(transactionHashes) { return __awaiter(this, void 0, void 0, function* () { const data = yield this.daemon.getTransactionsStatus({ transactionHashes, }); return data.transactionsUnknown || []; }); } /** * Gets random outputs for the given amounts. requestedOuts per. Usually mixin+1. * * @returns Returns an array of amounts to global indexes and keys. There * should be requestedOuts indexes if the daemon fully fulfilled * our request. */ getRandomOutputsByAmount(amounts, requestedOuts) { return __awaiter(this, void 0, void 0, function* () { let data; try { data = yield this.daemon.getRandomOutputs({ amounts: amounts, mixin: requestedOuts, }); } catch (err) { Logger_1.logger.log('Failed to get random outs: ' + err.toString(), Logger_1.LogLevel.ERROR, [Logger_1.LogCategory.TRANSACTIONS, Logger_1.LogCategory.DAEMON]); return []; } /* Most likely daemon is busy */ if (data.status !== 'OK') { Logger_1.logger.log('Failed to get random outputs, got status ' + data.status + ' from daemon.', Logger_1.LogLevel.ERROR, [Logger_1.LogCategory.TRANSACTIONS, Logger_1.LogCategory.DAEMON]); return []; } const outputs = []; for (const output of data.outs) { const indexes = []; for (const outs of output.outs) { indexes.push([outs.global_amount_index, outs.out_key]); } /* Sort by output index to make it hard to determine real one */ outputs.push([output.amount, _.sortBy(indexes, ([index, key]) => index)]); } return outputs; }); } sendTransaction(rawTransaction) { return __awaiter(this, void 0, void 0, function* () { const result = yield this.daemon.sendRawTransaction({ tx: rawTransaction, }); return result.status === 'OK'; }); } getConnectionInfo() { return { host: this.daemonHost, port: this.daemonPort, daemonType: Types_1.DaemonType.ConventionalDaemon, daemonTypeDetermined: true, ssl: false, sslDetermined: true, }; } /** * Update the fee address and amount */ updateFeeInfo() { return __awaiter(this, void 0, void 0, function* () { let feeInfo; try { feeInfo = yield this.daemon.fee(); } catch (err) { Logger_1.logger.log('Failed to update fee info: ' + err.toString(), Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]); return; } /* Most likely daemon is busy */ if (feeInfo.status !== 'OK') { Logger_1.logger.log('Failed to update fee info, got status ' + feeInfo.status + ' from daemon.', Logger_1.LogLevel.INFO, [Logger_1.LogCategory.DAEMON]); return; } if (feeInfo.address === '') { return; } const integratedAddressesAllowed = false; const err = ValidateParameters_1.validateAddresses(new Array(feeInfo.address), integratedAddressesAllowed, this.config).errorCode; if (err !== WalletError_1.WalletErrorCode.SUCCESS) { Logger_1.logger.log('Failed to validate address from daemon fee info: ' + err.toString(), Logger_1.LogLevel.WARNING, [Logger_1.LogCategory.DAEMON]); return; } if (feeInfo.amount > 0) { this.feeAddress = feeInfo.address; this.feeAmount = feeInfo.amount; } }); } } exports.ConventionalDaemon = ConventionalDaemon;