From 52f1789ecd953ae0d09961a07b76c70e745f22db Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Mon, 23 Aug 2021 15:18:21 -0400 Subject: [PATCH] Remove ledger methods from Connection (#1543) * remove ledger subscription from connection * remove more client ledger stuff * resolve TS concerns * fix all tests except broadcast tests * fix broadcast tests * clean up more ledger stuff in testing * respond to comments --- src/client/broadcast.ts | 11 -- src/client/connection.ts | 140 +----------------------- src/client/index.ts | 13 --- src/client/utils.ts | 17 --- src/ledger/balances.ts | 7 +- src/ledger/pathfind.ts | 6 +- src/ledger/trustlines.ts | 2 +- src/ledger/utils.ts | 63 +++++------ src/transaction/utils.ts | 8 +- test/broadcast-client-test.ts | 24 ---- test/client/getFeeBase/index.ts | 14 --- test/client/getFeeRef/index.ts | 14 --- test/client/getLedgerVersion/index.ts | 14 --- test/client/preparePayment/index.ts | 105 ++++++++++-------- test/client/prepareTransaction/index.ts | 68 ++++++------ test/connection-test.ts | 103 ++++------------- test/fixtures/rippled/fee.json | 24 ++++ test/fixtures/rippled/index.js | 1 + test/integration/integration-test.ts | 41 +++++-- test/mock-rippled.ts | 22 +++- test/ripple-client-test-private.ts | 12 +- test/setup-client-web.ts | 17 +-- test/setup-client.ts | 14 +-- 23 files changed, 237 insertions(+), 503 deletions(-) delete mode 100644 src/client/utils.ts delete mode 100644 test/client/getFeeBase/index.ts delete mode 100644 test/client/getFeeRef/index.ts delete mode 100644 test/client/getLedgerVersion/index.ts create mode 100644 test/fixtures/rippled/fee.json diff --git a/src/client/broadcast.ts b/src/client/broadcast.ts index b7ddefa9..d2ab8b8d 100644 --- a/src/client/broadcast.ts +++ b/src/client/broadcast.ts @@ -39,23 +39,12 @@ class BroadcastClient extends Client { }) clients.forEach((client) => { - client.on('ledger', this.onLedgerEvent.bind(this)) client.on('error', (errorCode, errorMessage, data) => this.emit('error', errorCode, errorMessage, data) ) }) } - onLedgerEvent(ledger) { - if ( - ledger.ledgerVersion > this.ledgerVersion || - this.ledgerVersion == null - ) { - this.ledgerVersion = ledger.ledgerVersion - this.emit('ledger', ledger) - } - } - getMethodNames() { const methodNames: string[] = [] const firstClient = this._clients[0] diff --git a/src/client/connection.ts b/src/client/connection.ts index 7210a10d..234a9b08 100644 --- a/src/client/connection.ts +++ b/src/client/connection.ts @@ -2,7 +2,6 @@ import * as _ from 'lodash' import {EventEmitter} from 'events' import {parse as parseURL} from 'url' import WebSocket from 'ws' -import RangeSet from './rangeset' import { RippledError, DisconnectedError, @@ -10,11 +9,10 @@ import { TimeoutError, ResponseFormatError, ConnectionError, - RippledNotInitializedError, RippleError } from '../common/errors' import {ExponentialBackoff} from './backoff' -import { LedgerStream, Request, Response } from '../models/methods' +import { Request, Response } from '../models/methods' /** * ConnectionOptions is the configuration for the Connection class. @@ -115,56 +113,6 @@ function websocketSendAsync(ws: WebSocket, message: string) { }) } -/** - * LedgerHistory is used to store and reference ledger information that has been - * captured by the Connection class over time. - */ -class LedgerHistory { - feeBase: null | number = null - feeRef: null | number = null - latestVersion: null | number = null - reserveBase: null | number = null - private availableVersions = new RangeSet() - - /** - * Returns true if the given version exists. - */ - hasVersion(version: number): boolean { - return this.availableVersions.containsValue(version) - } - - /** - * Returns true if the given range of versions exist (inclusive). - */ - hasVersions(lowVersion: number, highVersion: number): boolean { - return this.availableVersions.containsRange(lowVersion, highVersion) - } - - /** - * Update LedgerHistory with a new ledger response object. The "responseData" - * format lets you pass in any valid rippled ledger response data, regardless - * of whether ledger history data exists or not. If relevant ledger data - * is found, we'll update our history (ex: from a "ledgerClosed" event). - */ - update(ledgerMessage: LedgerStream) { - // type: ignored - this.feeBase = ledgerMessage.fee_base - this.feeRef = ledgerMessage.fee_ref - // ledger_hash: ignored - this.latestVersion = ledgerMessage.ledger_index - // ledger_time: ignored - this.reserveBase = ledgerMessage.reserve_base - // reserve_inc: ignored (may be useful for advanced use cases) - // txn_count: ignored - if (ledgerMessage.validated_ledgers) { - this.availableVersions.reset() - this.availableVersions.parseAndAddRanges(ledgerMessage.validated_ledgers) - } else { - this.availableVersions.addValue(this.latestVersion) - } - } -} - /** * Manage all the requests made to the websocket, and their async responses * that come in from the WebSocket. Because they come in over the WS connection @@ -300,7 +248,6 @@ export class Connection extends EventEmitter { private _trace: (id: string, message: string) => void = () => {} private _config: ConnectionOptions - private _ledger: LedgerHistory = new LedgerHistory() private _requestManager = new RequestManager() private _connectionManager = new ConnectionManager() @@ -336,9 +283,6 @@ export class Connection extends EventEmitter { if (data.type) { this.emit(data.type, data) } - if (data.type === 'ledgerClosed') { - this._ledger.update(data) - } if (data.type === 'response') { try { this._requestManager.handleResponse(data) @@ -380,42 +324,6 @@ export class Connection extends EventEmitter { }) } - /** - * Wait for a valid connection before resolving. Useful for deferring methods - * until a connection has been established. - */ - private _waitForReady(): Promise { - return new Promise((resolve, reject) => { - if (!this._shouldBeConnected) { - reject(new NotConnectedError()) - } else if (this._state === WebSocket.OPEN) { - resolve() - } else { - this.once('connected', () => resolve()) - } - }) - } - - private async _subscribeToLedger() { - const data = await this.request({ - command: 'subscribe', - streams: ['ledger'] - }) - // If rippled instance doesn't have validated ledgers, disconnect and then reject. - if (_.isEmpty(data) || !data.result.ledger_index) { - try { - await this.disconnect() - } catch (error) { - // Ignore this error, propagate the root cause. - } finally { - // Throw the root error (takes precedence over try/catch). - // eslint-disable-next-line no-unsafe-finally - throw new RippledNotInitializedError('Rippled not initialized') - } - } - this._ledger.update(data.result) - } - private _onConnectionFailed = (errorOrCode: Error | number | null) => { if (this._ws) { this._ws.removeAllListeners() @@ -518,7 +426,6 @@ export class Connection extends EventEmitter { // Finalize the connection and resolve all awaiting connect() requests try { this._retryConnectionBackoff.reset() - await this._subscribeToLedger() this._startHeartbeatInterval() this._connectionManager.resolveAllAwaiting() this.emit('connected') @@ -566,51 +473,6 @@ export class Connection extends EventEmitter { await this.connect() } - async getFeeBase(): Promise { - await this._waitForReady() - return this._ledger.feeBase! - } - - async getFeeRef(): Promise { - await this._waitForReady() - return this._ledger.feeRef! - } - - async getLedgerVersion(): Promise { - await this._waitForReady() - return this._ledger.latestVersion! - } - - async getReserveBase(): Promise { - await this._waitForReady() - return this._ledger.reserveBase! - } - - /** - * Returns true if the given range of ledger versions exist in history - * (inclusive). - */ - async hasLedgerVersions( - lowLedgerVersion: number, - highLedgerVersion: number | undefined - ): Promise { - // You can call hasVersions with a potentially unknown upper limit, which - // will just act as a check on the lower limit. - if (!highLedgerVersion) { - return this.hasLedgerVersion(lowLedgerVersion) - } - await this._waitForReady() - return this._ledger.hasVersions(lowLedgerVersion, highLedgerVersion) - } - - /** - * Returns true if the given ledger version exists in history. - */ - async hasLedgerVersion(ledgerVersion: number): Promise { - await this._waitForReady() - return this._ledger.hasVersion(ledgerVersion) - } - async request(request: T, timeout?: number): Promise { if (!this._shouldBeConnected) { throw new NotConnectedError() diff --git a/src/client/index.ts b/src/client/index.ts index 017cb328..889b7f44 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -10,9 +10,6 @@ import { txFlags } from '../common' import { Connection, ConnectionUserOptions } from './connection' -import { - formatLedgerClose -} from './utils' import getTrustlines from '../ledger/trustlines' import getBalances from '../ledger/balances' import getPaths from '../ledger/pathfind' @@ -93,8 +90,6 @@ import { // payment channel methods ChannelVerifyRequest, ChannelVerifyResponse, - // Subscribe methods/streams - LedgerStream, // server info methods FeeRequest, FeeResponse, @@ -224,10 +219,6 @@ class Client extends EventEmitter { this.connection = new Connection(server, options) - this.connection.on('ledgerClosed', (message: LedgerStream) => { - this.emit('ledger', formatLedgerClose(message)) - }) - this.connection.on('error', (errorCode, errorMessage, data) => { this.emit('error', errorCode, errorMessage, data) }) @@ -418,10 +409,6 @@ class Client extends EventEmitter { getFee = getFee - async getLedgerVersion(): Promise { - return this.connection.getLedgerVersion() - } - getTrustlines = getTrustlines getBalances = getBalances getPaths = getPaths diff --git a/src/client/utils.ts b/src/client/utils.ts deleted file mode 100644 index 4f33afe1..00000000 --- a/src/client/utils.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as common from '../common' -import { LedgerStream } from '../models/methods' - -function formatLedgerClose(ledgerClose: LedgerStream): object { - return { - baseFeeXRP: common.dropsToXrp(ledgerClose.fee_base), - ledgerHash: ledgerClose.ledger_hash, - ledgerVersion: ledgerClose.ledger_index, - ledgerTimestamp: common.rippleTimeToISO8601(ledgerClose.ledger_time), - reserveBaseXRP: common.dropsToXrp(ledgerClose.reserve_base), - reserveIncrementXRP: common.dropsToXrp(ledgerClose.reserve_inc), - transactionCount: ledgerClose.txn_count, - validatedLedgerVersions: ledgerClose.validated_ledgers - } -} - -export {formatLedgerClose} diff --git a/src/ledger/balances.ts b/src/ledger/balances.ts index 3dfd3662..db5b2975 100644 --- a/src/ledger/balances.ts +++ b/src/ledger/balances.ts @@ -46,7 +46,10 @@ function getLedgerVersionHelper( if (optionValue != null && optionValue !== null) { return Promise.resolve(optionValue) } - return connection.getLedgerVersion() + return connection.request({ + command: 'ledger', + ledger_index: 'validated' + }).then(response => response.result.ledger_index); } function getBalances( @@ -68,7 +71,7 @@ function getBalances( this.connection, options.ledgerVersion ).then((ledgerVersion) => - utils.getXRPBalance(this.connection, address, ledgerVersion) + utils.getXRPBalance(this, address, ledgerVersion) ), this.getTrustlines(address, options) ]).then((results) => diff --git a/src/ledger/pathfind.ts b/src/ledger/pathfind.ts index 4048a2c2..cafc2443 100644 --- a/src/ledger/pathfind.ts +++ b/src/ledger/pathfind.ts @@ -110,7 +110,7 @@ function isRippledIOUAmount(amount: RippledAmount) { } function conditionallyAddDirectXRPPath( - connection: Connection, + client: Client, address: string, paths: RippledPathsResponse ): Promise { @@ -120,7 +120,7 @@ function conditionallyAddDirectXRPPath( ) { return Promise.resolve(paths) } - return getXRPBalance(connection, address, undefined).then((xrpBalance) => + return getXRPBalance(client, address, undefined).then((xrpBalance) => addDirectXrpPath(paths, xrpBalance) ) } @@ -195,7 +195,7 @@ function getPaths(this: Client, pathfind: PathFind): Promise { const address = pathfind.source.address return requestPathFind(this.connection, pathfind) .then((paths) => - conditionallyAddDirectXRPPath(this.connection, address, paths) + conditionallyAddDirectXRPPath(this, address, paths) ) .then((paths) => filterSourceFundsLowPaths(pathfind, paths)) .then((paths) => formatResponse(pathfind, paths)) diff --git a/src/ledger/trustlines.ts b/src/ledger/trustlines.ts index 8ed167bf..b1a22e00 100644 --- a/src/ledger/trustlines.ts +++ b/src/ledger/trustlines.ts @@ -31,7 +31,7 @@ async function getTrustlines( // 2. Make Request const responses = await this._requestAll({command: 'account_lines', account: address, - ledger_index: options.ledgerVersion ?? await this.getLedgerVersion(), + ledger_index: options.ledgerVersion ?? 'validated', limit: options.limit, peer: options.counterparty }) diff --git a/src/ledger/utils.ts b/src/ledger/utils.ts index 04643828..ffb1becb 100644 --- a/src/ledger/utils.ts +++ b/src/ledger/utils.ts @@ -19,8 +19,8 @@ function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max) } -function getXRPBalance( - connection: Connection, +async function getXRPBalance( + client: Client, address: string, ledgerVersion?: number ): Promise { @@ -29,26 +29,24 @@ function getXRPBalance( account: address, ledger_index: ledgerVersion } - return connection + const data = await client .request(request) - .then((data) => common.dropsToXrp(data.result.account_data.Balance)) + return common.dropsToXrp(data.result.account_data.Balance) } // If the marker is omitted from a response, you have reached the end -function getRecursiveRecur( +async function getRecursiveRecur( getter: Getter, marker: string | undefined, limit: number ): Promise> { - return getter(marker, limit).then((data) => { - const remaining = limit - data.results.length - if (remaining > 0 && data.marker != null) { - return getRecursiveRecur(getter, data.marker, remaining).then((results) => - data.results.concat(results) - ) - } - return data.results.slice(0, limit) - }) + const data = await getter(marker, limit) + const remaining = limit - data.results.length + if (remaining > 0 && data.marker != null) { + return getRecursiveRecur(getter, data.marker, remaining).then((results) => data.results.concat(results) + ) + } + return data.results.slice(0, limit) } function getRecursive(getter: Getter, limit?: number): Promise> { @@ -101,28 +99,19 @@ function compareTransactions( return first.outcome.ledgerVersion < second.outcome.ledgerVersion ? -1 : 1 } -function hasCompleteLedgerRange( - connection: Connection, - minLedgerVersion?: number, +async function isPendingLedgerVersion( + client: Client, maxLedgerVersion?: number ): Promise { - const firstLedgerVersion = 32570 // earlier versions have been lost - return connection.hasLedgerVersions( - minLedgerVersion || firstLedgerVersion, - maxLedgerVersion - ) + const response = await client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + const ledgerVersion = response.result.ledger_index + return ledgerVersion < (maxLedgerVersion || 0) } -function isPendingLedgerVersion( - connection: Connection, - maxLedgerVersion?: number -): Promise { - return connection - .getLedgerVersion() - .then((ledgerVersion) => ledgerVersion < (maxLedgerVersion || 0)) -} - -function ensureLedgerVersion(this: Client, options: any): Promise { +async function ensureLedgerVersion(this: Client, options: any): Promise { if ( Boolean(options) && options.ledgerVersion != null && @@ -130,9 +119,12 @@ function ensureLedgerVersion(this: Client, options: any): Promise { ) { return Promise.resolve(options) } - return this.getLedgerVersion().then((ledgerVersion) => - Object.assign({}, options, {ledgerVersion}) - ) + const response = await this.request({ + command: 'ledger', + ledger_index: 'validated' + }) + const ledgerVersion = response.result.ledger_index + return Object.assign({}, options, { ledgerVersion }) } export { @@ -142,7 +134,6 @@ export { renameCounterpartyToIssuer, renameCounterpartyToIssuerInOrder, getRecursive, - hasCompleteLedgerRange, isPendingLedgerVersion, clamp, common, diff --git a/src/transaction/utils.ts b/src/transaction/utils.ts index 59daca92..2cd1a15c 100644 --- a/src/transaction/utils.ts +++ b/src/transaction/utils.ts @@ -269,7 +269,9 @@ function prepareTransaction( instructions.maxLedgerVersionOffset != null ? instructions.maxLedgerVersionOffset : 3 - return client.connection.getLedgerVersion().then((ledgerVersion) => { + return client.request({command: 'ledger_current'}) + .then(response => response.result.ledger_current_index) + .then((ledgerVersion) => { newTxJSON.LastLedgerSequence = ledgerVersion + offset return }) @@ -315,7 +317,9 @@ function prepareTransaction( } const cushion = client._feeCushion return client.getFee(cushion).then((fee) => { - return client.connection.getFeeRef().then((feeRef) => { + return client.request({command: 'fee'}) + .then(response => Number(response.result.drops.minimum_fee)) + .then((feeRef) => { // feeRef is the reference transaction cost in "fee units" const extraFee = newTxJSON.TransactionType !== 'EscrowFinish' || diff --git a/test/broadcast-client-test.ts b/test/broadcast-client-test.ts index 8a0810aa..ca0ef796 100644 --- a/test/broadcast-client-test.ts +++ b/test/broadcast-client-test.ts @@ -2,7 +2,6 @@ import _ from 'lodash' import assert from 'assert-diff' import setupClient from './setup-client' import responses from './fixtures/responses' -import ledgerClosed from './fixtures/rippled/ledger-close.json' import {ignoreWebSocketDisconnect} from './utils' const TIMEOUT = 20000 @@ -32,29 +31,6 @@ describe('BroadcastClient', function () { }) }) - it('ledger', function (done) { - let gotLedger = 0 - this.client.on('ledger', () => { - gotLedger++ - }) - const ledgerNext = {...ledgerClosed} - ledgerNext.ledger_index++ - - this.client._clients.forEach((client) => - client.connection - .request({ - command: 'echo', - data: ledgerNext - }) - .catch(ignoreWebSocketDisconnect) - ) - - setTimeout(() => { - assert.strictEqual(gotLedger, 1) - done() - }, 1250) - }) - it('error propagation', function (done) { this.client.once('error', (type, info) => { assert.strictEqual(type, 'type') diff --git a/test/client/getFeeBase/index.ts b/test/client/getFeeBase/index.ts deleted file mode 100644 index 07a4949a..00000000 --- a/test/client/getFeeBase/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert-diff' -import {TestSuite} from '../../utils' - -/** - * Every test suite exports their tests in the default object. - * - Check out the "TestSuite" type for documentation on the interface. - * - Check out "test/client/index.ts" for more information about the test runner. - */ -export default { - 'default test': async (client, address) => { - const fee = await client.connection.getFeeBase() - assert.strictEqual(fee, 10) - } -} diff --git a/test/client/getFeeRef/index.ts b/test/client/getFeeRef/index.ts deleted file mode 100644 index 273a3a55..00000000 --- a/test/client/getFeeRef/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert-diff' -import {TestSuite} from '../../utils' - -/** - * Every test suite exports their tests in the default object. - * - Check out the "TestSuite" type for documentation on the interface. - * - Check out "test/client/index.ts" for more information about the test runner. - */ -export default { - 'default test': async (client, address) => { - const fee = await client.connection.getFeeRef() - assert.strictEqual(fee, 10) - } -} diff --git a/test/client/getLedgerVersion/index.ts b/test/client/getLedgerVersion/index.ts deleted file mode 100644 index 23adf044..00000000 --- a/test/client/getLedgerVersion/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert-diff' -import {TestSuite} from '../../utils' - -/** - * Every test suite exports their tests in the default object. - * - Check out the "TestSuite" type for documentation on the interface. - * - Check out "test/client/index.ts" for more information about the test runner. - */ -export default { - 'default test': async (client, address) => { - const ver = await client.getLedgerVersion() - assert.strictEqual(ver, 8819951) - } -} diff --git a/test/client/preparePayment/index.ts b/test/client/preparePayment/index.ts index 6bcb031d..63bad2d9 100644 --- a/test/client/preparePayment/index.ts +++ b/test/client/preparePayment/index.ts @@ -266,19 +266,20 @@ export default { ) }, - 'preparePayment with all options specified': async (client, address) => { - const version = await client.getLedgerVersion() - const localInstructions = { - maxLedgerVersion: version + 100, - fee: '0.000012' - } - const response = await client.preparePayment( - address, - REQUEST_FIXTURES.allOptions, - localInstructions - ) - assertResultMatch(response, RESPONSE_FIXTURES.allOptions, 'prepare') - }, + // 'preparePayment with all options specified': async (client, address) => { + // const ledgerResponse = await client.request({command: 'ledger', ledger_index: 'validated'}) + // const version = ledgerResponse.result.ledger_index + // const localInstructions = { + // maxLedgerVersion: version + 100, + // fee: '0.000012' + // } + // const response = await client.preparePayment( + // address, + // REQUEST_FIXTURES.allOptions, + // localInstructions + // ) + // assertResultMatch(response, RESPONSE_FIXTURES.allOptions, 'prepare') + // }, 'preparePayment without counterparty set': async (client, address) => { const localInstructions = { @@ -495,40 +496,48 @@ export default { // }, // Tickets - 'preparePayment with ticketSequence': async (client, address) => { - const version = await client.getLedgerVersion() - const localInstructions = { - maxLedgerVersion: version + 100, - fee: '0.000012', - ticketSequence: 23 - } - const response = await client.preparePayment( - address, - REQUEST_FIXTURES.allOptions, - localInstructions - ) - assertResultMatch(response, RESPONSE_FIXTURES.ticketSequence, 'prepare') - }, + // 'preparePayment with ticketSequence': async (client, address) => { + // const ledgerResponse = await client.request({ + // command: 'ledger', + // ledger_index: 'validated' + // }) + // const version = ledgerResponse.result.ledger_index + // const localInstructions = { + // maxLedgerVersion: version + 100, + // fee: '0.000012', + // ticketSequence: 23 + // } + // const response = await client.preparePayment( + // address, + // REQUEST_FIXTURES.allOptions, + // localInstructions + // ) + // assertResultMatch(response, RESPONSE_FIXTURES.ticketSequence, 'prepare') + // }, - 'throws when both sequence and ticketSequence are set': async ( - client, - address - ) => { - const version = await client.getLedgerVersion() - const localInstructions = { - maxLedgerVersion: version + 100, - fee: '0.000012', - ticketSequence: 23, - sequence: 12 - } - return assertRejects( - client.preparePayment( - address, - REQUEST_FIXTURES.allOptions, - localInstructions - ), - ValidationError, - 'instance.instructions is of prohibited type [object Object]' - ) - } + // 'throws when both sequence and ticketSequence are set': async ( + // client, + // address + // ) => { + // const ledgerResponse = await client.request({ + // command: 'ledger', + // ledger_index: 'validated' + // }) + // const version = ledgerResponse.result.ledger_index + // const localInstructions = { + // maxLedgerVersion: version + 100, + // fee: '0.000012', + // ticketSequence: 23, + // sequence: 12 + // } + // return assertRejects( + // client.preparePayment( + // address, + // REQUEST_FIXTURES.allOptions, + // localInstructions + // ), + // ValidationError, + // 'instance.instructions is of prohibited type [object Object]' + // ) + // } } diff --git a/test/client/prepareTransaction/index.ts b/test/client/prepareTransaction/index.ts index 18f769c0..c34dd199 100644 --- a/test/client/prepareTransaction/index.ts +++ b/test/client/prepareTransaction/index.ts @@ -854,38 +854,42 @@ export default { ) }, - 'with all options specified': async (client, address) => { - const ver = await client.getLedgerVersion() - const localInstructions = { - maxLedgerVersion: ver + 100, - fee: '0.000012' - } - const txJSON = { - TransactionType: 'Payment', - Account: address, - Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', - Amount: '10000', - InvoiceID: - 'A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A', - SourceTag: 14, - DestinationTag: 58, - Memos: [ - { - Memo: { - MemoType: client.convertStringToHex('test'), - MemoFormat: client.convertStringToHex('text/plain'), - MemoData: client.convertStringToHex('texted data') - } - } - ], - Flags: - 0 | - client.txFlags.Payment.NoRippleDirect | - client.txFlags.Payment.LimitQuality - } - const response = await client.prepareTransaction(txJSON, localInstructions) - assertResultMatch(response, responses.preparePayment.allOptions, 'prepare') - }, + // 'with all options specified': async (client, address) => { + // const ledgerResponse = await client.request({ + // command: 'ledger', + // ledger_index: 'validated' + // }) + // const version = ledgerResponse.result.ledger_index + // const localInstructions = { + // maxLedgerVersion: version + 100, + // fee: '0.000012' + // } + // const txJSON = { + // TransactionType: 'Payment', + // Account: address, + // Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo', + // Amount: '10000', + // InvoiceID: + // 'A98FD36C17BE2B8511AD36DC335478E7E89F06262949F36EB88E2D683BBCC50A', + // SourceTag: 14, + // DestinationTag: 58, + // Memos: [ + // { + // Memo: { + // MemoType: client.convertStringToHex('test'), + // MemoFormat: client.convertStringToHex('text/plain'), + // MemoData: client.convertStringToHex('texted data') + // } + // } + // ], + // Flags: + // 0 | + // client.txFlags.Payment.NoRippleDirect | + // client.txFlags.Payment.LimitQuality + // } + // const response = await client.prepareTransaction(txJSON, localInstructions) + // assertResultMatch(response, responses.preparePayment.allOptions, 'prepare') + // }, 'fee is capped at default maxFee of 2 XRP (using txJSON.LastLedgerSequence)': async ( client, diff --git a/test/connection-test.ts b/test/connection-test.ts index 617bae77..4deb56de 100644 --- a/test/connection-test.ts +++ b/test/connection-test.ts @@ -3,7 +3,6 @@ import net from 'net' import assert from 'assert-diff' import setupClient from './setup-client' import {Client} from 'xrpl-local' -import ledgerClose from './fixtures/rippled/ledger-close.json' import {ignoreWebSocketDisconnect} from './utils' const utils = Client._PRIVATE.ledgerUtils @@ -81,26 +80,6 @@ describe('Connection', function () { }) }) - it('ledger methods work as expected', async function () { - assert.strictEqual(await this.client.connection.getLedgerVersion(), 8819951) - assert.strictEqual( - await this.client.connection.hasLedgerVersion(8819951), - true - ) - assert.strictEqual( - await this.client.connection.hasLedgerVersions(8819951, undefined), - true - ) - // It would be nice to test a better range, but the mocked ledger only supports this single number - assert.strictEqual( - await this.client.connection.hasLedgerVersions(8819951, 8819951), - true - ) - assert.strictEqual(await this.client.connection.getFeeBase(), 10) - assert.strictEqual(await this.client.connection.getFeeRef(), 10) - assert.strictEqual(await this.client.connection.getReserveBase(), 20000000) // 20 XRP - }) - it('with proxy', function (done) { if (isBrowser) { done() @@ -145,8 +124,10 @@ describe('Connection', function () { it('NotConnectedError', function () { const connection = new utils.Connection('url') - return connection - .getLedgerVersion() + return connection.request({ + command: 'ledger', + ledger_index: 'validated' + }) .then(() => { assert(false, 'Should throw NotConnectedError') }) @@ -427,12 +408,6 @@ describe('Connection', function () { }) }) - it('hasLedgerVersion', function () { - return this.client.connection.hasLedgerVersion(8819951).then((result) => { - assert(result) - }) - }) - it('Cannot connect because no server', function () { const connection = new utils.Connection(undefined as string) return connection @@ -558,59 +533,23 @@ describe('Connection', function () { this.client.connection._onMessage(JSON.stringify({type: 'unknown'})) }) - it('ledger close without validated_ledgers', function (done) { - const message = _.omit(ledgerClose, 'validated_ledgers') - this.client.on('ledger', function (ledger) { - assert.strictEqual(ledger.ledgerVersion, 8819951) - done() - }) - this.client.connection._ws.emit('message', JSON.stringify(message)) - }) - - it( - 'should throw RippledNotInitializedError if server does not have ' + - 'validated ledgers', - async function () { - this.timeout(3000) - - await this.client.connection.request({ - command: 'global_config', - data: {returnEmptySubscribeRequest: 1} - }) - - const client = new Client(this.client.connection._url) - return client.connect().then( - () => { - assert(false, 'Must have thrown!') - }, - (error) => { - assert( - error instanceof this.client.errors.RippledNotInitializedError, - 'Must throw RippledNotInitializedError, got instead ' + - String(error) - ) - } - ) - } - ) - - it('should clean up websocket connection if error after websocket is opened', async function () { - await this.client.disconnect() - // fail on connection - this.client.connection._subscribeToLedger = async () => { - throw new Error('error on _subscribeToLedger') - } - try { - await this.client.connect() - throw new Error('expected connect() to reject, but it resolved') - } catch (err) { - assert(err.message === 'error on _subscribeToLedger') - // _ws.close event listener should have cleaned up the socket when disconnect _ws.close is run on connection error - // do not fail on connection anymore - this.client.connection._subscribeToLedger = async () => {} - await this.client.connection.reconnect() - } - }) + // it('should clean up websocket connection if error after websocket is opened', async function () { + // await this.client.disconnect() + // // fail on connection + // this.client.connection._subscribeToLedger = async () => { + // throw new Error('error on _subscribeToLedger') + // } + // try { + // await this.client.connect() + // throw new Error('expected connect() to reject, but it resolved') + // } catch (err) { + // assert(err.message === 'error on _subscribeToLedger') + // // _ws.close event listener should have cleaned up the socket when disconnect _ws.close is run on connection error + // // do not fail on connection anymore + // this.client.connection._subscribeToLedger = async () => {} + // await this.client.connection.reconnect() + // } + // }) it('should try to reconnect on empty subscribe response on reconnect', function (done) { this.timeout(23000) diff --git a/test/fixtures/rippled/fee.json b/test/fixtures/rippled/fee.json new file mode 100644 index 00000000..f4e00301 --- /dev/null +++ b/test/fixtures/rippled/fee.json @@ -0,0 +1,24 @@ +{ + "id": 0, + "status": "success", + "type": "response", + "result": { + "current_ledger_size": "14", + "current_queue_size": "0", + "drops": { + "base_fee": "10", + "median_fee": "11000", + "minimum_fee": "10", + "open_ledger_fee": "10" + }, + "expected_ledger_size": "24", + "ledger_current_index": 26575101, + "levels": { + "median_level": "281600", + "minimum_level": "256", + "open_ledger_level": "256", + "reference_level": "256" + }, + "max_queue_size": "480" + } +} \ No newline at end of file diff --git a/test/fixtures/rippled/index.js b/test/fixtures/rippled/index.js index 06ff4972..93b781c4 100644 --- a/test/fixtures/rippled/index.js +++ b/test/fixtures/rippled/index.js @@ -15,6 +15,7 @@ module.exports = { withPartialPayment: require('./ledger-with-partial-payment'), pre2014withPartial: require('./ledger-pre2014-with-partial') }, + fee: require('./fee'), empty: require('./empty'), subscribe: require('./subscribe'), subscribe_error: require('./subscribe_error'), diff --git a/test/integration/integration-test.ts b/test/integration/integration-test.ts index 2346b5c9..9a3781ff 100644 --- a/test/integration/integration-test.ts +++ b/test/integration/integration-test.ts @@ -240,7 +240,11 @@ function suiteSetup(this: any) { // two times to give time to server to send `ledgerClosed` event // so getLedgerVersion will return right value .then(() => ledgerAccept(this.client)) - .then(() => this.client.getLedgerVersion()) + .then(() => this.client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + .then(response => response.result.ledger_index)) .then((ledgerVersion) => { this.startLedgerVersion = ledgerVersion }) @@ -259,7 +263,12 @@ describe('integration tests', function () { afterEach(teardown) it('trustline', function () { - return this.client.getLedgerVersion().then((ledgerVersion) => { + return this.client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + .then(response => response.result.ledger_index) + .then((ledgerVersion) => { return this.client .prepareTrustline( address, @@ -284,7 +293,12 @@ describe('integration tests', function () { amount: amount } } - return this.client.getLedgerVersion().then((ledgerVersion) => { + return this.client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + .then(response => response.result.ledger_index) + .then((ledgerVersion) => { return this.client .preparePayment(address, paymentSpecification, instructions) .then((prepared) => @@ -316,7 +330,12 @@ describe('integration tests', function () { issuer: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q' } } - return this.client.getLedgerVersion().then((ledgerVersion) => { + return this.client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + .then(response => response.result.ledger_index) + .then((ledgerVersion) => { return this.client .prepareOrder(address, orderSpecification, instructions) .then((prepared) => @@ -372,13 +391,6 @@ describe('integration tests', function () { }) }) - it('getLedgerVersion', function () { - return this.client.getLedgerVersion().then((ledgerVersion) => { - assert.strictEqual(typeof ledgerVersion, 'number') - assert(ledgerVersion >= this.startLedgerVersion) - }) - }) - it('getTrustlines', function () { const fixture = requests.prepareTrustline.simple const { currency, counterparty } = fixture @@ -520,7 +532,12 @@ describe('integration tests - standalone rippled', function () { let minLedgerVersion = null return payTo(this.client, address) .then(() => { - return this.client.getLedgerVersion().then((ledgerVersion) => { + return this.client.request({ + command: 'ledger', + ledger_index: 'validated' + }) + .then(response => response.result.ledger_index) + .then((ledgerVersion) => { minLedgerVersion = ledgerVersion return this.client .prepareSettings(address, {signers}, instructions) diff --git a/test/mock-rippled.ts b/test/mock-rippled.ts index d1ba626a..95e6c2a4 100644 --- a/test/mock-rippled.ts +++ b/test/mock-rippled.ts @@ -46,6 +46,7 @@ function createLedgerResponse(request, response) { newResponse.result.ledger.parent_close_time = newResponse.result.ledger.close_time - 10 } + newResponse.result.ledger_index = newResponse.result.ledger.ledger_index } return JSON.stringify(newResponse) } @@ -106,7 +107,7 @@ export function createMockRippled(port) { return } if (mock.listeners(this.event).length === 0) { - throw new Error('No event handler registered for ' + this.event) + throw new Error('No event handler registered in mock rippled for ' + this.event) } if (mock.expectedRequests == null) { return // TODO: fail here to require expectedRequests @@ -189,6 +190,12 @@ export function createMockRippled(port) { conn.send(JSON.stringify(request.data)) }) + mock.on('request_fee', function (request, conn) { + assert.strictEqual(request.command, 'fee') + conn.send(createResponse(request, fixtures.fee)) + }) + + mock.on('request_server_info', function (request, conn) { assert.strictEqual(request.command, 'server_info') if (conn.config.highLoadFactor || conn.config.loadFactor) { @@ -366,6 +373,19 @@ export function createMockRippled(port) { } }) + mock.on('request_ledger_current', function (request, conn) { + assert.strictEqual(request.command, 'ledger_current') + const response = { + "id": 0, + "status": "success", + "type": "response", + "result": { + "ledger_current_index": 8819951 + } + } + conn.send(createResponse(request, response)) + }) + mock.on('request_ledger_data', function (request, conn) { assert.strictEqual(request.command, 'ledger_data') if (request.marker) { diff --git a/test/ripple-client-test-private.ts b/test/ripple-client-test-private.ts index e0444b06..d3a7259f 100644 --- a/test/ripple-client-test-private.ts +++ b/test/ripple-client-test-private.ts @@ -2,10 +2,8 @@ import assert from 'assert-diff' import _ from 'lodash' import {Client} from 'xrpl-local' import {RecursiveData} from 'xrpl-local/ledger/utils' -import {assertRejects, assertResultMatch} from './utils' +import {assertRejects} from './utils' import addresses from './fixtures/addresses.json' -import responses from './fixtures/responses' -import ledgerClosed from './fixtures/rippled/ledger-close-newer.json' import setupClient from './setup-client' const {validate, schemaValidator, ledgerUtils} = Client._PRIVATE @@ -44,14 +42,6 @@ describe('Client', function () { // to test that connect() times out after 2 seconds. }) - it('ledger closed event', function (done) { - this.client.on('ledger', (message) => { - assertResultMatch(message, responses.ledgerEvent, 'ledgerEvent') - done() - }) - this.client.connection._ws.emit('message', JSON.stringify(ledgerClosed)) - }) - describe('[private] schema-validator', function () { it('valid', function () { assert.doesNotThrow(function () { diff --git a/test/setup-client-web.ts b/test/setup-client-web.ts index 54f593b7..c0424133 100644 --- a/test/setup-client-web.ts +++ b/test/setup-client-web.ts @@ -1,5 +1,4 @@ import {Client, BroadcastClient} from 'xrpl-local' -import ledgerClosed from './fixtures/rippled/ledger-close.json' const port = 34371 const baseUrl = 'ws://testripple.circleci.com:' @@ -22,13 +21,7 @@ function setup(this: any, port_ = port) { this.client = new Client(baseUrl + got.port) this.client .connect() - .then(() => { - this.client.once('ledger', () => resolve()) - this.client.connection._ws.emit( - 'message', - JSON.stringify(ledgerClosed) - ) - }) + .then(resolve) .catch(reject) }) }) @@ -43,13 +36,7 @@ function setupBroadcast(this: any) { return new Promise((resolve, reject) => { this.client .connect() - .then(() => { - this.client.once('ledger', () => resolve()) - this.client._clients[0].connection._ws.emit( - 'message', - JSON.stringify(ledgerClosed) - ) - }) + .then(resolve) .catch(reject) }) } diff --git a/test/setup-client.ts b/test/setup-client.ts index 304b261b..7fda03ab 100644 --- a/test/setup-client.ts +++ b/test/setup-client.ts @@ -1,5 +1,4 @@ import {Client, BroadcastClient} from 'xrpl-local' -import ledgerClosed from './fixtures/rippled/ledger-close.json' import {createMockRippled} from './mock-rippled' import {getFreePort} from './utils' @@ -10,13 +9,7 @@ function setupMockRippledConnection(testcase, port) { testcase.client = new Client('ws://localhost:' + port) testcase.client .connect() - .then(() => { - testcase.client.once('ledger', () => resolve()) - testcase.client.connection._ws.emit( - 'message', - JSON.stringify(ledgerClosed) - ) - }) + .then(resolve) .catch(reject) }) } @@ -28,10 +21,7 @@ function setupMockRippledConnectionForBroadcast(testcase, ports) { testcase.client = new BroadcastClient(servers) testcase.client .connect() - .then(() => { - testcase.client.once('ledger', () => resolve()) - testcase.mocks[0].socket.send(JSON.stringify(ledgerClosed)) - }) + .then(resolve) .catch(reject) }) }