diff --git a/CHANGELOG.md b/CHANGELOG.md index b20a3732e1..99c05aca1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## [4.1.25] - 2023.11.2 +## [4.1.26] - 2023.11.12 +### Fixed +- Fixed `LoadBalancer` throwing from setTimeout, it should now throw from actual method calls. + +## [4.1.25] - 2023.11.10 ### Added - Added RPC support for the ALGORAND network. Users can now make RPC calls to these network using the `Network.ALGORAND_ALGOD`, `Network.ALGORAND_ALGOD_TESTNET`, `Network.ALGORAND_INDEXER`, `Network.ALGORAND_INDEXER_TESTNET` network. diff --git a/package.json b/package.json index 522f3f5b2e..bb5389498c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tatumio/tatum", - "version": "4.1.25", + "version": "4.1.26", "description": "Tatum JS SDK", "author": "Tatum", "repository": "https://github.com/tatumio/tatum-js", diff --git a/src/dto/rpc/index.ts b/src/dto/rpc/index.ts index 6fecbdb186..c27408cfce 100644 --- a/src/dto/rpc/index.ts +++ b/src/dto/rpc/index.ts @@ -1,6 +1,6 @@ export * from './EvmBasedRpcInterface' export * from './SolanaRpcSuite' +export * from './TezosRpcSuite' export * from './TronRpcSuite' export * from './UtxoBasedRpcSuite' export * from './XrpRpcSuite' -export * from './TezosRpcSuite' diff --git a/src/dto/shared.dto.ts b/src/dto/shared.dto.ts index 5b9a872ec0..b154ea59c8 100644 --- a/src/dto/shared.dto.ts +++ b/src/dto/shared.dto.ts @@ -83,6 +83,6 @@ export interface TokenDetails { export type QueryValue = string | number | boolean | string[] | number[] | boolean[] export type QueryParams = Record export type SendGet = { - path: string, + path: string queryParams?: QueryParams } diff --git a/src/e2e/rpc/other/tatum.rpc.tezos.spec.ts b/src/e2e/rpc/other/tatum.rpc.tezos.spec.ts index 9d938d1a12..3d47dc4e3a 100644 --- a/src/e2e/rpc/other/tatum.rpc.tezos.spec.ts +++ b/src/e2e/rpc/other/tatum.rpc.tezos.spec.ts @@ -41,11 +41,11 @@ describe.each([false, true])(`Tezos`, (testnet: boolean) => { chainId: 'main', contractId: 'KT1Hkg5qeNhfwpKW4fXvq7HGZB9z2EnmCCA9', block: '3000000', - normalizeTypes: true - }) - await tatum.destroy() - expect(result).toBeDefined() + normalizeTypes: true, }) + await tatum.destroy() + expect(result).toBeDefined() + }) it('getContractBalanceAndFrozenBonds', async () => { const tatum = await getTezosRpc(testnet) diff --git a/src/service/rpc/evm/AbstractBeaconV1EvmRpc.ts b/src/service/rpc/evm/AbstractBeaconV1EvmRpc.ts index d35fbabdaf..890a19cbe6 100644 --- a/src/service/rpc/evm/AbstractBeaconV1EvmRpc.ts +++ b/src/service/rpc/evm/AbstractBeaconV1EvmRpc.ts @@ -3,12 +3,13 @@ import { BlockQuery, EvmBeaconResponse, EvmBeaconV1Interface, + QueryParams, StateCommitteesQuery, StateQuery, StateSyncCommitteesQuery, ValidatorBalancesQuery, ValidatorQuery, - ValidatorsQuery, QueryParams, + ValidatorsQuery, } from '../../../dto' import { GetI } from '../../../dto/GetI' import { Constant, Utils } from '../../../util' @@ -17,16 +18,16 @@ export abstract class AbstractBeaconV1EvmRpc implements EvmBeaconV1Interface { protected abstract get(get: GetI): Promise private sendGet(path: string, params: QueryParams): Promise { - const fullPath = Utils.addQueryParams(`${Constant.BEACON_PREFIX}/${path}`, Utils.camelToSnakeCase, params); - return this.get({ path: fullPath }); + const fullPath = Utils.addQueryParams(`${Constant.BEACON_PREFIX}/${path}`, Utils.camelToSnakeCase, params) + return this.get({ path: fullPath }) } getBlockAttestations({ blockId, ...rest }: BlockQuery): Promise> { - return this.sendGet(`blocks/${blockId}/attestations`, rest); + return this.sendGet(`blocks/${blockId}/attestations`, rest) } getBlockHeader({ blockId, ...rest }: BlockQuery): Promise> { - return this.sendGet(`blocks/${blockId}/header`, rest); + return this.sendGet(`blocks/${blockId}/header`, rest) } getBlockHeaders({ slot, parentRoot, ...rest }: { slot?: string; parentRoot?: string } = {}): Promise< @@ -35,48 +36,48 @@ export abstract class AbstractBeaconV1EvmRpc implements EvmBeaconV1Interface { const queryParams = { ...(slot ? { slot } : {}), ...(parentRoot ? { parentRoot } : {}), - ...rest - }; - return this.sendGet(`headers`, queryParams); + ...rest, + } + return this.sendGet(`headers`, queryParams) } getBlockRoot({ blockId, ...rest }: BlockQuery): Promise> { - return this.sendGet(`blocks/${blockId}/root`, rest); + return this.sendGet(`blocks/${blockId}/root`, rest) } getGenesis(): Promise> { - return this.sendGet('genesis', {}); + return this.sendGet('genesis', {}) } getStateCommittees({ stateId, ...rest }: StateCommitteesQuery): Promise> { - return this.sendGet(`states/${stateId}/committees`, rest); + return this.sendGet(`states/${stateId}/committees`, rest) } getStateFinalityCheckpoints({ stateId, ...rest }: StateQuery): Promise> { - return this.sendGet(`states/${stateId}/finality_checkpoints`, rest); + return this.sendGet(`states/${stateId}/finality_checkpoints`, rest) } getStateFork({ stateId, ...rest }: StateQuery): Promise> { - return this.sendGet(`states/${stateId}/fork`, rest); + return this.sendGet(`states/${stateId}/fork`, rest) } getStateRoot({ stateId, ...rest }: StateQuery): Promise> { - return this.sendGet(`states/${stateId}/root`, rest); + return this.sendGet(`states/${stateId}/root`, rest) } getStateSyncCommittees({ stateId, ...rest }: StateSyncCommitteesQuery): Promise> { - return this.sendGet(`states/${stateId}/sync_committees`, rest); + return this.sendGet(`states/${stateId}/sync_committees`, rest) } getStateValidator({ stateId, validatorId, ...rest }: ValidatorQuery): Promise> { - return this.sendGet(`states/${stateId}/validators/${validatorId}`, rest); + return this.sendGet(`states/${stateId}/validators/${validatorId}`, rest) } getStateValidatorBalances({ stateId, ...rest }: ValidatorBalancesQuery): Promise> { - return this.sendGet(`states/${stateId}/validator_balances`, rest); + return this.sendGet(`states/${stateId}/validator_balances`, rest) } getStateValidators({ stateId, ...rest }: ValidatorsQuery): Promise> { - return this.sendGet(`states/${stateId}/validators`, rest); + return this.sendGet(`states/${stateId}/validators`, rest) } } diff --git a/src/service/rpc/generic/LoadBalancer.ts b/src/service/rpc/generic/LoadBalancer.ts index 38fb95d479..14a52d97d7 100644 --- a/src/service/rpc/generic/LoadBalancer.ts +++ b/src/service/rpc/generic/LoadBalancer.ts @@ -77,6 +77,7 @@ export class LoadBalancer implements AbstractRpcInterface { } private timeout: unknown private network: Network + private noActiveNode = false constructor(private readonly id: string) { this.connector = Container.of(this.id).get(TatumConnector) @@ -140,10 +141,7 @@ export class LoadBalancer implements AbstractRpcInterface { private async checkStatuses() { await this.checkStatus(RpcNodeType.NORMAL) await this.checkStatus(RpcNodeType.ARCHIVE) - if (!this.activeUrl[RpcNodeType.NORMAL].url && !this.activeUrl[RpcNodeType.ARCHIVE].url) { - Utils.log({ id: this.id, message: 'No active node found, please set node urls manually.' }) - throw new Error('No active node found, please set node urls manually.') - } + this.checkIfNoActiveNodes() const { rpc } = Container.of(this.id).get(CONFIG) if (!rpc?.oneTimeLoadBalancing) { @@ -154,6 +152,15 @@ export class LoadBalancer implements AbstractRpcInterface { } } + private checkIfNoActiveNodes() { + if (!this.activeUrl[RpcNodeType.NORMAL].url && !this.activeUrl[RpcNodeType.ARCHIVE].url) { + Utils.log({ id: this.id, message: 'No active node found, please set node urls manually.' }) + this.noActiveNode = true + } else { + this.noActiveNode = false + } + } + private async checkStatus(nodeType: RpcNodeType) { const { rpc, network } = Container.of(this.id).get(CONFIG) const all = [] @@ -268,6 +275,10 @@ export class LoadBalancer implements AbstractRpcInterface { return { url: this.getActiveUrl(RpcNodeType.NORMAL).url, type: RpcNodeType.NORMAL } } + if (this.noActiveNode) { + throw new Error('No active node found, please set node urls manually.') + } + throw new Error('No active node found.') } @@ -281,6 +292,10 @@ export class LoadBalancer implements AbstractRpcInterface { return { url: this.getActiveUrl(RpcNodeType.ARCHIVE).url, type: RpcNodeType.ARCHIVE } } + if (this.noActiveNode) { + throw new Error('No active node found, please set node urls manually.') + } + throw new Error('No active node found.') } diff --git a/src/service/rpc/other/AbstractTezosRpc.ts b/src/service/rpc/other/AbstractTezosRpc.ts index e1abaf827a..6ca5d98c3b 100644 --- a/src/service/rpc/other/AbstractTezosRpc.ts +++ b/src/service/rpc/other/AbstractTezosRpc.ts @@ -1,9 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Service } from 'typedi' -import { QueryParams } from '../../../dto' -import { GetI } from '../../../dto/GetI' -import { PostI } from '../../../dto/PostI' import { GetBlock, GetBlockHashes, @@ -18,9 +15,12 @@ import { InjectOperation, InjectProtocol, PreapplyOperations, + QueryParams, SimulateOperation, TezosRpcInterface, } from '../../../dto' +import { GetI } from '../../../dto/GetI' +import { PostI } from '../../../dto/PostI' import { Utils } from '../../../util' @Service() @@ -28,13 +28,7 @@ export abstract class AbstractTezosRpc implements TezosRpcInterface { protected abstract get(post: GetI): Promise protected abstract post(post: PostI): Promise - private async sendGet({ - path, - queryParams, - }: { - path: string - queryParams?: QueryParams - }): Promise { + private async sendGet({ path, queryParams }: { path: string; queryParams?: QueryParams }): Promise { if (queryParams && Object.keys(queryParams).length > 0) { return this.get({ path: Utils.addQueryParams(path, Utils.camelToSnakeCase, queryParams) }) } diff --git a/src/service/rpc/other/AlgorandAlgodLoadBalancerRpc.ts b/src/service/rpc/other/AlgorandAlgodLoadBalancerRpc.ts index df36884cd7..6cc3eaaff7 100644 --- a/src/service/rpc/other/AlgorandAlgodLoadBalancerRpc.ts +++ b/src/service/rpc/other/AlgorandAlgodLoadBalancerRpc.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Container, Service } from 'typedi' -import { LoadBalancer } from '../generic/LoadBalancer' import { GetI } from '../../../dto/GetI' import { PostI } from '../../../dto/PostI' +import { LoadBalancer } from '../generic' import { AbstractAlgorandAlgodRpc } from './AbstractAlgorandAlgodRpc' @Service({ diff --git a/src/service/rpc/other/AlgorandIndexerLoadBalancerRpc.ts b/src/service/rpc/other/AlgorandIndexerLoadBalancerRpc.ts index 7c887359e2..195770b2a3 100644 --- a/src/service/rpc/other/AlgorandIndexerLoadBalancerRpc.ts +++ b/src/service/rpc/other/AlgorandIndexerLoadBalancerRpc.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Container, Service } from 'typedi' -import { LoadBalancer } from '../generic/LoadBalancer' import { GetI } from '../../../dto/GetI' +import { LoadBalancer } from '../generic' import { AbstractAlgorandIndexerRpc } from './AbstractAlgorandIndexerRpc' @Service({ diff --git a/src/service/tatum/tatum.other.ts b/src/service/tatum/tatum.other.ts index d66ec09fd3..21c98b171c 100644 --- a/src/service/tatum/tatum.other.ts +++ b/src/service/tatum/tatum.other.ts @@ -1,5 +1,8 @@ import { Container } from 'typedi' -import { SolanaRpcSuite, TronRpcSuite, XrpRpcInterface } from '../../dto' +import { SolanaRpcSuite, TezosRpcInterface, TronRpcSuite, XrpRpcInterface } from '../../dto' +import { AlgorandAlgodRpcSuite } from '../../dto/rpc/AlgorandAlgodRpcSuite' +import { AlgorandIndexerRpcSuite } from '../../dto/rpc/AlgorandIndexerRpcSuite' +import { BnbRpcSuite } from '../../dto/rpc/BnbRpcSuite' import { EosRpcSuite } from '../../dto/rpc/EosRpcSuite' import { CONFIG, Utils } from '../../util' import { Address, AddressTezos, AddressTron } from '../address' @@ -10,10 +13,6 @@ import { Notification } from '../notification' import { Rates } from '../rate' import { Token } from '../token' import { TatumSdkChain } from './tatum' -import { BnbRpcSuite } from '../../dto/rpc/BnbRpcSuite' -import { TezosRpcInterface } from '../../dto/rpc/TezosRpcSuite' -import { AlgorandAlgodRpcSuite } from '../../dto/rpc/AlgorandAlgodRpcSuite' -import { AlgorandIndexerRpcSuite } from '../../dto/rpc/AlgorandIndexerRpcSuite' export abstract class BaseOther extends TatumSdkChain { ipfs: Ipfs