mirror of
				https://github.com/Xahau/xahau.js.git
				synced 2025-11-04 04:55:48 +00:00 
			
		
		
		
	feature NetworkID (#2216)
				
					
				
			Added network id to the base transaction Added network id to the server_info response Added network id to the binary codec Added network id to client and modify on client.connect() Added network id to autofill when rippled_version is 1.11.0 or later or network is hooks testnet Co-authored-by: Phu Pham <ppham@ripple.com> Co-authored-by: pdp2121 <71317875+pdp2121@users.noreply.github.com> Co-authored-by: Jackson Mills <aim4math@gmail.com> Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
This commit is contained in:
		@@ -321,6 +321,16 @@
 | 
			
		||||
        "type": "UInt16"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      "NetworkID",
 | 
			
		||||
      {
 | 
			
		||||
        "nth": 1,
 | 
			
		||||
        "isVLEncoded": false,
 | 
			
		||||
        "isSerialized": true,
 | 
			
		||||
        "isSigningField": true,
 | 
			
		||||
        "type": "UInt32"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      "Flags",
 | 
			
		||||
      {
 | 
			
		||||
@@ -2176,6 +2186,9 @@
 | 
			
		||||
    "telCAN_NOT_QUEUE_BLOCKED": -389,
 | 
			
		||||
    "telCAN_NOT_QUEUE_FEE": -388,
 | 
			
		||||
    "telCAN_NOT_QUEUE_FULL": -387,
 | 
			
		||||
    "telWRONG_NETWORK": -386,
 | 
			
		||||
    "telREQUIRES_NETWORK_ID": -385,
 | 
			
		||||
    "telNETWORK_ID_MAKES_TX_NON_CANONICAL": -384,
 | 
			
		||||
 | 
			
		||||
    "temMALFORMED": -299,
 | 
			
		||||
    "temBAD_AMOUNT": -298,
 | 
			
		||||
 
 | 
			
		||||
@@ -205,6 +205,18 @@ class Client extends EventEmitter {
 | 
			
		||||
   */
 | 
			
		||||
  public readonly maxFeeXRP: string
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Network ID of the server this client is connected to
 | 
			
		||||
   *
 | 
			
		||||
   */
 | 
			
		||||
  public networkID: number | undefined
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Rippled Version used by the server this client is connected to
 | 
			
		||||
   *
 | 
			
		||||
   */
 | 
			
		||||
  public buildVersion: string | undefined
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Creates a new Client with a websocket connection to a rippled server.
 | 
			
		||||
   *
 | 
			
		||||
@@ -230,8 +242,8 @@ class Client extends EventEmitter {
 | 
			
		||||
      this.emit('error', errorCode, errorMessage, data)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    this.connection.on('connected', () => {
 | 
			
		||||
      this.emit('connected')
 | 
			
		||||
    this.connection.on('reconnect', () => {
 | 
			
		||||
      this.connection.on('connected', () => this.emit('connected'))
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    this.connection.on('disconnected', (code: number) => {
 | 
			
		||||
@@ -568,6 +580,22 @@ class Client extends EventEmitter {
 | 
			
		||||
    return results
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get networkID and buildVersion from server_info
 | 
			
		||||
   */
 | 
			
		||||
  public async getServerInfo(): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
      const response = await this.request({
 | 
			
		||||
        command: 'server_info',
 | 
			
		||||
      })
 | 
			
		||||
      this.networkID = response.result.info.network_id ?? undefined
 | 
			
		||||
      this.buildVersion = response.result.info.build_version
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      // eslint-disable-next-line no-console -- Print the error to console but allows client to be connected.
 | 
			
		||||
      console.error(error)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tells the Client instance to connect to its rippled server.
 | 
			
		||||
   *
 | 
			
		||||
@@ -588,7 +616,10 @@ class Client extends EventEmitter {
 | 
			
		||||
   * @category Network
 | 
			
		||||
   */
 | 
			
		||||
  public async connect(): Promise<void> {
 | 
			
		||||
    return this.connection.connect()
 | 
			
		||||
    return this.connection.connect().then(async () => {
 | 
			
		||||
      await this.getServerInfo()
 | 
			
		||||
      this.emit('connected')
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 
 | 
			
		||||
@@ -136,6 +136,10 @@ export interface ServerInfoResponse extends BaseResponse {
 | 
			
		||||
       * overall network's load factor.
 | 
			
		||||
       */
 | 
			
		||||
      load_factor?: number
 | 
			
		||||
      /**
 | 
			
		||||
       * The network id of the server.
 | 
			
		||||
       */
 | 
			
		||||
      network_id?: number
 | 
			
		||||
      /**
 | 
			
		||||
       * Current multiplier to the transaction cost based on
 | 
			
		||||
       * load to this server.
 | 
			
		||||
 
 | 
			
		||||
@@ -157,6 +157,10 @@ export interface BaseTransaction {
 | 
			
		||||
   * account it says it is from.
 | 
			
		||||
   */
 | 
			
		||||
  TxnSignature?: string
 | 
			
		||||
  /**
 | 
			
		||||
   * The network id of the transaction.
 | 
			
		||||
   */
 | 
			
		||||
  NetworkID?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -250,6 +254,9 @@ export function validateBaseTransaction(common: Record<string, unknown>): void {
 | 
			
		||||
  ) {
 | 
			
		||||
    throw new ValidationError('BaseTransaction: invalid TxnSignature')
 | 
			
		||||
  }
 | 
			
		||||
  if (common.NetworkID !== undefined && typeof common.NetworkID !== 'number') {
 | 
			
		||||
    throw new ValidationError('BaseTransaction: invalid NetworkID')
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,13 @@ import getFeeXrp from './getFeeXrp'
 | 
			
		||||
 | 
			
		||||
// Expire unconfirmed transactions after 20 ledger versions, approximately 1 minute, by default
 | 
			
		||||
const LEDGER_OFFSET = 20
 | 
			
		||||
// Sidechains are expected to have network IDs above this.
 | 
			
		||||
// Networks with ID above this restricted number are expected specify an accurate NetworkID field
 | 
			
		||||
// in every transaction to that chain to prevent replay attacks.
 | 
			
		||||
// Mainnet and testnet are exceptions. More context: https://github.com/XRPLF/rippled/pull/4370
 | 
			
		||||
const RESTRICTED_NETWORKS = 1024
 | 
			
		||||
const REQUIRED_NETWORKID_VERSION = '1.11.0'
 | 
			
		||||
const HOOKS_TESTNET_ID = 21338
 | 
			
		||||
interface ClassicAccountAndTag {
 | 
			
		||||
  classicAccount: string
 | 
			
		||||
  tag: number | false | undefined
 | 
			
		||||
@@ -70,8 +77,10 @@ async function autofill<T extends Transaction>(
 | 
			
		||||
  setValidAddresses(tx)
 | 
			
		||||
 | 
			
		||||
  setTransactionFlagsToNumber(tx)
 | 
			
		||||
 | 
			
		||||
  const promises: Array<Promise<void>> = []
 | 
			
		||||
  if (tx.NetworkID == null) {
 | 
			
		||||
    tx.NetworkID = txNeedsNetworkID(this) ? this.networkID : undefined
 | 
			
		||||
  }
 | 
			
		||||
  if (tx.Sequence == null) {
 | 
			
		||||
    promises.push(setNextValidSequenceNumber(this, tx))
 | 
			
		||||
  }
 | 
			
		||||
@@ -88,6 +97,101 @@ async function autofill<T extends Transaction>(
 | 
			
		||||
  return Promise.all(promises).then(() => tx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Determines whether the source rippled version is not later than the target rippled version.
 | 
			
		||||
 * Example usage: isNotLaterRippledVersion('1.10.0', '1.11.0') returns true.
 | 
			
		||||
 *                isNotLaterRippledVersion('1.10.0', '1.10.0-b1') returns false.
 | 
			
		||||
 *
 | 
			
		||||
 * @param source -- The source rippled version.
 | 
			
		||||
 * @param target -- The target rippled version.
 | 
			
		||||
 * @returns True if source is earlier than target, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
// eslint-disable-next-line max-lines-per-function, max-statements -- Disable for this helper functions.
 | 
			
		||||
function isNotLaterRippledVersion(source: string, target: string): boolean {
 | 
			
		||||
  if (source === target) {
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
  const sourceDecomp = source.split('.')
 | 
			
		||||
  const targetDecomp = target.split('.')
 | 
			
		||||
  const sourceMajor = parseInt(sourceDecomp[0], 10)
 | 
			
		||||
  const sourceMinor = parseInt(sourceDecomp[1], 10)
 | 
			
		||||
  const targetMajor = parseInt(targetDecomp[0], 10)
 | 
			
		||||
  const targetMinor = parseInt(targetDecomp[1], 10)
 | 
			
		||||
  // Compare major version
 | 
			
		||||
  if (sourceMajor !== targetMajor) {
 | 
			
		||||
    return sourceMajor < targetMajor
 | 
			
		||||
  }
 | 
			
		||||
  // Compare minor version
 | 
			
		||||
  if (sourceMinor !== targetMinor) {
 | 
			
		||||
    return sourceMinor < targetMinor
 | 
			
		||||
  }
 | 
			
		||||
  const sourcePatch = sourceDecomp[2].split('-')
 | 
			
		||||
  const targetPatch = targetDecomp[2].split('-')
 | 
			
		||||
 | 
			
		||||
  const sourcePatchVersion = parseInt(sourcePatch[0], 10)
 | 
			
		||||
  const targetPatchVersion = parseInt(targetPatch[0], 10)
 | 
			
		||||
 | 
			
		||||
  // Compare patch version
 | 
			
		||||
  if (sourcePatchVersion !== targetPatchVersion) {
 | 
			
		||||
    return sourcePatchVersion < targetPatchVersion
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Compare release version
 | 
			
		||||
  if (sourcePatch.length !== targetPatch.length) {
 | 
			
		||||
    return sourcePatch.length > targetPatch.length
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (sourcePatch.length === 2) {
 | 
			
		||||
    // Compare different release types
 | 
			
		||||
    if (!sourcePatch[1][0].startsWith(targetPatch[1][0])) {
 | 
			
		||||
      return sourcePatch[1] < targetPatch[1]
 | 
			
		||||
    }
 | 
			
		||||
    // Compare beta version
 | 
			
		||||
    if (sourcePatch[1].startsWith('b')) {
 | 
			
		||||
      return (
 | 
			
		||||
        parseInt(sourcePatch[1].slice(1), 10) <
 | 
			
		||||
        parseInt(targetPatch[1].slice(1), 10)
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
    // Compare rc version
 | 
			
		||||
    return (
 | 
			
		||||
      parseInt(sourcePatch[1].slice(2), 10) <
 | 
			
		||||
      parseInt(targetPatch[1].slice(2), 10)
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Determine if the transaction required a networkID to be valid.
 | 
			
		||||
 * Transaction needs networkID if later than restricted ID and either the network is hooks testnet
 | 
			
		||||
 * or build version is >= 1.11.0
 | 
			
		||||
 *
 | 
			
		||||
 * @param client -- The connected client.
 | 
			
		||||
 * @returns True if required networkID, false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
function txNeedsNetworkID(client: Client): boolean {
 | 
			
		||||
  if (
 | 
			
		||||
    client.networkID !== undefined &&
 | 
			
		||||
    client.networkID > RESTRICTED_NETWORKS
 | 
			
		||||
  ) {
 | 
			
		||||
    // TODO: remove the buildVersion logic when 1.11.0 is out and widely used.
 | 
			
		||||
    // Issue: https://github.com/XRPLF/xrpl.js/issues/2339
 | 
			
		||||
    if (
 | 
			
		||||
      (client.buildVersion &&
 | 
			
		||||
        isNotLaterRippledVersion(
 | 
			
		||||
          REQUIRED_NETWORKID_VERSION,
 | 
			
		||||
          client.buildVersion,
 | 
			
		||||
        )) ||
 | 
			
		||||
      client.networkID === HOOKS_TESTNET_ID
 | 
			
		||||
    ) {
 | 
			
		||||
      return true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setValidAddresses(tx: Transaction): void {
 | 
			
		||||
  validateAccountAddress(tx, 'Account', 'SourceTag')
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/dot-notation -- Destination can exist on Transaction
 | 
			
		||||
 
 | 
			
		||||
@@ -15,13 +15,32 @@ import {
 | 
			
		||||
} from '../setupClient'
 | 
			
		||||
import { assertRejects } from '../testUtils'
 | 
			
		||||
 | 
			
		||||
const NetworkID = 1025
 | 
			
		||||
const Fee = '10'
 | 
			
		||||
const Sequence = 1432
 | 
			
		||||
const LastLedgerSequence = 2908734
 | 
			
		||||
const HOOKS_TESTNET_ID = 21338
 | 
			
		||||
 | 
			
		||||
describe('client.autofill', function () {
 | 
			
		||||
  let testContext: XrplTestContext
 | 
			
		||||
 | 
			
		||||
  async function setupMockRippledVersionAndID(
 | 
			
		||||
    buildVersion: string,
 | 
			
		||||
    networkID: number,
 | 
			
		||||
  ): Promise<void> {
 | 
			
		||||
    await testContext.client.disconnect()
 | 
			
		||||
    rippled.server_info.withNetworkId.result.info.build_version = buildVersion
 | 
			
		||||
    rippled.server_info.withNetworkId.result.info.network_id = networkID
 | 
			
		||||
    testContext.client.connection.on('connected', () => {
 | 
			
		||||
      testContext.mockRippled?.addResponse(
 | 
			
		||||
        'server_info',
 | 
			
		||||
        rippled.server_info.withNetworkId,
 | 
			
		||||
      )
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    await testContext.client.connect()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    testContext = await setupClient()
 | 
			
		||||
  })
 | 
			
		||||
@@ -32,17 +51,116 @@ describe('client.autofill', function () {
 | 
			
		||||
      TransactionType: 'DepositPreauth',
 | 
			
		||||
      Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
 | 
			
		||||
      Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
 | 
			
		||||
      NetworkID,
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, NetworkID)
 | 
			
		||||
    assert.strictEqual(txResult.Fee, Fee)
 | 
			
		||||
    assert.strictEqual(txResult.Sequence, Sequence)
 | 
			
		||||
    assert.strictEqual(txResult.LastLedgerSequence, LastLedgerSequence)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('ignores network ID if missing', async function () {
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
 | 
			
		||||
      Amount: '1234',
 | 
			
		||||
      Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
 | 
			
		||||
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, undefined)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // NetworkID is required in transaction for network > 1024 and from version 1.11.0 or later.
 | 
			
		||||
  // More context: https://github.com/XRPLF/rippled/pull/4370
 | 
			
		||||
  it('overrides network ID if > 1024 and version is later than 1.11.0', async function () {
 | 
			
		||||
    await setupMockRippledVersionAndID('1.11.1', 1025)
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
 | 
			
		||||
      Amount: '1234',
 | 
			
		||||
      Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
 | 
			
		||||
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, 1025)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // NetworkID is only required in transaction for version 1.11.0 or later.
 | 
			
		||||
  // More context: https://github.com/XRPLF/rippled/pull/4370
 | 
			
		||||
  it('ignores network ID if > 1024 but version is earlier than 1.11.0', async function () {
 | 
			
		||||
    await setupMockRippledVersionAndID('1.10.0', 1025)
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
 | 
			
		||||
      Amount: '1234',
 | 
			
		||||
      Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
 | 
			
		||||
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, undefined)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // NetworkID <= 1024 does not require a newtorkID in transaction.
 | 
			
		||||
  // More context: https://github.com/XRPLF/rippled/pull/4370
 | 
			
		||||
  it('ignores network ID if <= 1024', async function () {
 | 
			
		||||
    await setupMockRippledVersionAndID('1.11.1', 1023)
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
 | 
			
		||||
      Amount: '1234',
 | 
			
		||||
      Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
 | 
			
		||||
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, undefined)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // Hooks Testnet requires networkID in transaction regardless of version.
 | 
			
		||||
  // More context: https://github.com/XRPLF/rippled/pull/4370
 | 
			
		||||
  it('overrides network ID for hooks testnet', async function () {
 | 
			
		||||
    await setupMockRippledVersionAndID('1.10.1', HOOKS_TESTNET_ID)
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      Account: 'XVLhHMPHU98es4dbozjVtdWzVrDjtV18pX8yuPT7y4xaEHi',
 | 
			
		||||
      Amount: '1234',
 | 
			
		||||
      Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
 | 
			
		||||
      Fee,
 | 
			
		||||
      Sequence,
 | 
			
		||||
      LastLedgerSequence,
 | 
			
		||||
    }
 | 
			
		||||
    testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
 | 
			
		||||
 | 
			
		||||
    const txResult = await testContext.client.autofill(tx)
 | 
			
		||||
 | 
			
		||||
    assert.strictEqual(txResult.NetworkID, HOOKS_TESTNET_ID)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('converts Account & Destination X-address to their classic address', async function () {
 | 
			
		||||
    const tx: Payment = {
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ import type {
 | 
			
		||||
 | 
			
		||||
import { destroyServer, getFreePort } from './testUtils'
 | 
			
		||||
 | 
			
		||||
function createResponse(
 | 
			
		||||
export function createResponse(
 | 
			
		||||
  request: { id: number | string },
 | 
			
		||||
  response: Record<string, unknown>,
 | 
			
		||||
): string {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								packages/xrpl/test/fixtures/rippled/index.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								packages/xrpl/test/fixtures/rippled/index.ts
									
									
									
									
										vendored
									
									
								
							@@ -12,6 +12,7 @@ import iouPartialPayment from './partialPaymentIOU.json'
 | 
			
		||||
import xrpPartialPayment from './partialPaymentXRP.json'
 | 
			
		||||
import normalServerInfo from './serverInfo.json'
 | 
			
		||||
import highLoadFactor from './serverInfoHighLoadFactor.json'
 | 
			
		||||
import withNetworkIDServerInfo from './serverInfoNetworkID.json'
 | 
			
		||||
import consensusStream from './streams/consensusPhase.json'
 | 
			
		||||
import ledgerStream from './streams/ledger.json'
 | 
			
		||||
import manifestStream from './streams/manifest.json'
 | 
			
		||||
@@ -84,6 +85,7 @@ const ledger_data = {
 | 
			
		||||
const server_info = {
 | 
			
		||||
  normal: normalServerInfo,
 | 
			
		||||
  highLoadFactor,
 | 
			
		||||
  withNetworkId: withNetworkIDServerInfo,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const tx = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								packages/xrpl/test/fixtures/rippled/serverInfoNetworkID.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/xrpl/test/fixtures/rippled/serverInfoNetworkID.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
{
 | 
			
		||||
  "id": 0,
 | 
			
		||||
  "status": "success",
 | 
			
		||||
  "type": "response",
 | 
			
		||||
  "result": {
 | 
			
		||||
    "info": {
 | 
			
		||||
      "build_version": "1.11.0-rc2",
 | 
			
		||||
      "complete_ledgers": "37621036-38327626",
 | 
			
		||||
      "hostid": "JANE",
 | 
			
		||||
      "io_latency_ms": 1,
 | 
			
		||||
      "last_close": {
 | 
			
		||||
        "converge_time_s": 2,
 | 
			
		||||
        "proposers": 6
 | 
			
		||||
      },
 | 
			
		||||
      "load_factor": 1,
 | 
			
		||||
      "network_id": 1,
 | 
			
		||||
      "peers": 113,
 | 
			
		||||
      "pubkey_node": "n9L6MAkAvZKakewLSJPkCKLxuSQ9jrYXJBd2L4fouhpXauyFh6ZM",
 | 
			
		||||
      "server_state": "full",
 | 
			
		||||
      "validated_ledger": {
 | 
			
		||||
        "age": 0,
 | 
			
		||||
        "base_fee_xrp": 0.00001,
 | 
			
		||||
        "hash": "A219F66BB8C9992E80A3C93A5EA408CD54B8F47F2AC1246C271C495F833752BA",
 | 
			
		||||
        "reserve_base_xrp": 10,
 | 
			
		||||
        "reserve_inc_xrp": 2,
 | 
			
		||||
        "seq": 38327626
 | 
			
		||||
      },
 | 
			
		||||
      "validation_quorum": 5
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -22,7 +22,7 @@ describe('mock rippled tests', function () {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await assertRejects(
 | 
			
		||||
      testContext.client.request({ command: 'server_info' }),
 | 
			
		||||
      testContext.client.request({ command: 'account_info' }),
 | 
			
		||||
      RippledError,
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 
 | 
			
		||||
@@ -232,4 +232,17 @@ describe('BaseTransaction', function () {
 | 
			
		||||
      'BaseTransaction: invalid Memos',
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it(`Handles invalid NetworkID`, function () {
 | 
			
		||||
    const invalidNetworkID = {
 | 
			
		||||
      Account: 'r97KeayHuEsDwyU1yPBVtMLLoQr79QcRFe',
 | 
			
		||||
      TransactionType: 'Payment',
 | 
			
		||||
      NetworkID: '1024',
 | 
			
		||||
    }
 | 
			
		||||
    assert.throws(
 | 
			
		||||
      () => validateBaseTransaction(invalidNetworkID),
 | 
			
		||||
      ValidationError,
 | 
			
		||||
      'BaseTransaction: invalid NetworkID',
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import BroadcastClient from '../src/client/BroadcastClient'
 | 
			
		||||
import createMockRippled, {
 | 
			
		||||
  type MockedWebSocketServer,
 | 
			
		||||
} from './createMockRippled'
 | 
			
		||||
import rippled from './fixtures/rippled'
 | 
			
		||||
import { destroyServer, getFreePort } from './testUtils'
 | 
			
		||||
 | 
			
		||||
export interface XrplTestContext {
 | 
			
		||||
@@ -29,6 +30,10 @@ async function setupMockRippledConnection(
 | 
			
		||||
  context.client.on('error', () => {
 | 
			
		||||
    // We must have an error listener attached for reconnect errors
 | 
			
		||||
  })
 | 
			
		||||
  context.mockRippled?.addResponse(
 | 
			
		||||
    'server_info',
 | 
			
		||||
    rippled.server_info.withNetworkId,
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  return context.client.connect().then(() => context)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user