mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 20:25:48 +00:00
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
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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<void> {
|
||||
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<number> {
|
||||
await this._waitForReady()
|
||||
return this._ledger.feeBase!
|
||||
}
|
||||
|
||||
async getFeeRef(): Promise<number> {
|
||||
await this._waitForReady()
|
||||
return this._ledger.feeRef!
|
||||
}
|
||||
|
||||
async getLedgerVersion(): Promise<number> {
|
||||
await this._waitForReady()
|
||||
return this._ledger.latestVersion!
|
||||
}
|
||||
|
||||
async getReserveBase(): Promise<number> {
|
||||
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<boolean> {
|
||||
// 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<boolean> {
|
||||
await this._waitForReady()
|
||||
return this._ledger.hasVersion(ledgerVersion)
|
||||
}
|
||||
|
||||
async request<T extends Request, U extends Response>(request: T, timeout?: number): Promise<U> {
|
||||
if (!this._shouldBeConnected) {
|
||||
throw new NotConnectedError()
|
||||
|
||||
@@ -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<number> {
|
||||
return this.connection.getLedgerVersion()
|
||||
}
|
||||
|
||||
getTrustlines = getTrustlines
|
||||
getBalances = getBalances
|
||||
getPaths = getPaths
|
||||
|
||||
@@ -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}
|
||||
@@ -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) =>
|
||||
|
||||
@@ -110,7 +110,7 @@ function isRippledIOUAmount(amount: RippledAmount) {
|
||||
}
|
||||
|
||||
function conditionallyAddDirectXRPPath(
|
||||
connection: Connection,
|
||||
client: Client,
|
||||
address: string,
|
||||
paths: RippledPathsResponse
|
||||
): Promise<RippledPathsResponse> {
|
||||
@@ -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<GetPaths> {
|
||||
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))
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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<string> {
|
||||
@@ -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<Array<any>> {
|
||||
return getter(marker, limit).then((data) => {
|
||||
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 getRecursiveRecur(getter, data.marker, remaining).then((results) => data.results.concat(results)
|
||||
)
|
||||
}
|
||||
return data.results.slice(0, limit)
|
||||
})
|
||||
}
|
||||
|
||||
function getRecursive(getter: Getter, limit?: number): Promise<Array<any>> {
|
||||
@@ -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<boolean> {
|
||||
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<boolean> {
|
||||
return connection
|
||||
.getLedgerVersion()
|
||||
.then((ledgerVersion) => ledgerVersion < (maxLedgerVersion || 0))
|
||||
}
|
||||
|
||||
function ensureLedgerVersion(this: Client, options: any): Promise<object> {
|
||||
async function ensureLedgerVersion(this: Client, options: any): Promise<object> {
|
||||
if (
|
||||
Boolean(options) &&
|
||||
options.ledgerVersion != null &&
|
||||
@@ -130,9 +119,12 @@ function ensureLedgerVersion(this: Client, options: any): Promise<object> {
|
||||
) {
|
||||
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,
|
||||
|
||||
@@ -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' ||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const fee = await client.connection.getFeeBase()
|
||||
assert.strictEqual(fee, 10)
|
||||
}
|
||||
}
|
||||
@@ -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 <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const fee = await client.connection.getFeeRef()
|
||||
assert.strictEqual(fee, 10)
|
||||
}
|
||||
}
|
||||
@@ -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 <TestSuite>{
|
||||
'default test': async (client, address) => {
|
||||
const ver = await client.getLedgerVersion()
|
||||
assert.strictEqual(ver, 8819951)
|
||||
}
|
||||
}
|
||||
@@ -266,19 +266,20 @@ export default <TestSuite>{
|
||||
)
|
||||
},
|
||||
|
||||
'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 <TestSuite>{
|
||||
// },
|
||||
|
||||
// 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]'
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -854,38 +854,42 @@ export default <TestSuite>{
|
||||
)
|
||||
},
|
||||
|
||||
'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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
24
test/fixtures/rippled/fee.json
vendored
Normal file
24
test/fixtures/rippled/fee.json
vendored
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
1
test/fixtures/rippled/index.js
vendored
1
test/fixtures/rippled/index.js
vendored
@@ -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'),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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<void>((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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user