From 61579414e8271bf7f899aec7dcfccf7d45a1c329 Mon Sep 17 00:00:00 2001 From: Denis Davidyuk Date: Tue, 13 Feb 2024 17:53:36 +0700 Subject: [PATCH] refactor(node): split into NodeBase and NodeDirect --- src/AeSdkAepp.ts | 2 +- src/AeSdkBase.ts | 2 +- src/AeSdkMethods.ts | 2 +- src/account/Base.ts | 2 +- src/account/LedgerFactory.ts | 2 +- src/aens.ts | 2 +- src/aepp-wallet-communication/rpc/types.ts | 2 +- src/chain.ts | 3 +- src/contract/Contract.ts | 3 +- src/contract/delegation-signature.ts | 2 +- src/contract/ga.ts | 2 +- src/index-browser.ts | 2 +- src/{Node.ts => node/Base.ts} | 104 +-------------------- src/node/Direct.ts | 101 ++++++++++++++++++++ src/oracle.ts | 2 +- src/tx/builder/field-types/abi-version.ts | 2 +- src/tx/builder/field-types/ct-version.ts | 2 +- src/tx/builder/field-types/nonce.ts | 2 +- src/tx/builder/field-types/query-fee.ts | 2 +- src/tx/builder/field-types/ttl.ts | 2 +- src/tx/execution-cost.ts | 2 +- src/tx/validator.ts | 3 +- 22 files changed, 128 insertions(+), 120 deletions(-) rename src/{Node.ts => node/Base.ts} (51%) create mode 100644 src/node/Direct.ts diff --git a/src/AeSdkAepp.ts b/src/AeSdkAepp.ts index 483ace100c..214e795859 100644 --- a/src/AeSdkAepp.ts +++ b/src/AeSdkAepp.ts @@ -15,7 +15,7 @@ import { UnAuthorizedAccountError, RpcConnectionError, } from './utils/errors'; -import Node from './Node'; +import Node from './node/Direct'; import BrowserConnection from './aepp-wallet-communication/connection/Browser'; /** diff --git a/src/AeSdkBase.ts b/src/AeSdkBase.ts index 507ace5f9a..e17f4b495f 100644 --- a/src/AeSdkBase.ts +++ b/src/AeSdkBase.ts @@ -1,4 +1,4 @@ -import Node from './Node'; +import Node from './node/Direct'; import AccountBase from './account/Base'; import { CompilerError, DuplicateNodeError, NodeNotFoundError, NotImplementedError, TypeError, diff --git a/src/AeSdkMethods.ts b/src/AeSdkMethods.ts index ae6beeda9e..385eb39157 100644 --- a/src/AeSdkMethods.ts +++ b/src/AeSdkMethods.ts @@ -7,7 +7,7 @@ import createDelegationSignature from './contract/delegation-signature'; import * as contractGaMethods from './contract/ga'; import { buildTxAsync } from './tx/builder'; import { mapObject, UnionToIntersection } from './utils/other'; -import Node from './Node'; +import Node from './node/Direct'; import { TxParamsAsync } from './tx/builder/schema.generated'; import AccountBase from './account/Base'; import { Encoded } from './utils/encoder'; diff --git a/src/account/Base.ts b/src/account/Base.ts index 597475d548..8b6a48654c 100644 --- a/src/account/Base.ts +++ b/src/account/Base.ts @@ -1,5 +1,5 @@ import { Encoded } from '../utils/encoder'; -import Node from '../Node'; +import Node from '../node/Direct'; import CompilerBase from '../contract/compiler/Base'; import { AensName, ConsensusProtocolVersion, Int } from '../tx/builder/constants'; import { AciValue, Domain } from '../utils/typed-data'; diff --git a/src/account/LedgerFactory.ts b/src/account/LedgerFactory.ts index 568b72263b..9132e43fea 100644 --- a/src/account/LedgerFactory.ts +++ b/src/account/LedgerFactory.ts @@ -3,7 +3,7 @@ import AccountLedger, { CLA, GET_ADDRESS, GET_APP_CONFIGURATION } from './Ledger import { UnsupportedVersionError } from '../utils/errors'; import { Encoded } from '../utils/encoder'; import semverSatisfies from '../utils/semver-satisfies'; -import Node from '../Node'; +import Node from '../node/Direct'; /** * A factory class that generates instances of AccountLedger based on provided transport. diff --git a/src/aens.ts b/src/aens.ts index b1a2495f89..c903ecfeca 100644 --- a/src/aens.ts +++ b/src/aens.ts @@ -14,7 +14,7 @@ import { Encoded, Encoding } from './utils/encoder'; import { UnsupportedProtocolError } from './utils/errors'; import { sendTransaction, SendTransactionOptions, getName } from './chain'; import { buildTxAsync, BuildTxOptions } from './tx/builder'; -import { TransformNodeType } from './Node'; +import { TransformNodeType } from './node/Base'; import { NameEntry, NamePointer } from './apis/node'; import AccountBase from './account/Base'; import { AddressEncodings } from './tx/builder/field-types/address'; diff --git a/src/aepp-wallet-communication/rpc/types.ts b/src/aepp-wallet-communication/rpc/types.ts index fa6de15586..a522213266 100644 --- a/src/aepp-wallet-communication/rpc/types.ts +++ b/src/aepp-wallet-communication/rpc/types.ts @@ -1,7 +1,7 @@ import { Encoded } from '../../utils/encoder'; import { Domain, AciValue } from '../../utils/typed-data'; import { METHODS, SUBSCRIPTION_TYPES, WALLET_TYPE } from '../schema'; -import { TransformNodeType } from '../../Node'; +import { TransformNodeType } from '../../node/Base'; import { SignedTx } from '../../apis/node'; import { AensName } from '../../tx/builder/constants'; diff --git a/src/chain.ts b/src/chain.ts index 748c98dbde..381b229d0f 100644 --- a/src/chain.ts +++ b/src/chain.ts @@ -8,7 +8,8 @@ import { AensPointerContextError, DryRunError, InvalidAensNameError, TransactionError, TxTimedOutError, TxNotInChainError, InternalError, } from './utils/errors'; -import Node, { TransformNodeType } from './Node'; +import { TransformNodeType } from './node/Base'; +import Node from './node/Direct'; import { Account as AccountNode, ByteCode, ContractObject, DryRunResult, DryRunResults, Generation, KeyBlock, MicroBlockHeader, NameEntry, SignedTx, diff --git a/src/contract/Contract.ts b/src/contract/Contract.ts index 37c313f0b1..3665137841 100644 --- a/src/contract/Contract.ts +++ b/src/contract/Contract.ts @@ -37,7 +37,8 @@ import { ContractCallObject as NodeContractCallObject, Event as NodeEvent, } from '../apis/node'; import CompilerBase, { Aci } from './compiler/Base'; -import Node, { TransformNodeType } from '../Node'; +import { TransformNodeType } from '../node/Base'; +import Node from '../node/Direct'; import { getAccount, getContract, getContractByteCode, resolveName, txDryRun, sendTransaction, SendTransactionOptions, diff --git a/src/contract/delegation-signature.ts b/src/contract/delegation-signature.ts index a05c36e819..9d56a87502 100644 --- a/src/contract/delegation-signature.ts +++ b/src/contract/delegation-signature.ts @@ -3,7 +3,7 @@ import { ArgumentError } from '../utils/errors'; import { AensName } from '../tx/builder/constants'; import AccountBase from '../account/Base'; import { isNameValid } from '../tx/builder/helpers'; -import Node from '../Node'; +import Node from '../node/Direct'; function ensureOracleQuery(oq: string): asserts oq is Encoded.OracleQueryId { if (!oq.startsWith('oq_')) throw new ArgumentError('oq', 'oracle query', oq); diff --git a/src/contract/ga.ts b/src/contract/ga.ts index ab62070b93..44500b7ef0 100644 --- a/src/contract/ga.ts +++ b/src/contract/ga.ts @@ -14,7 +14,7 @@ import { ArgumentError, IllegalArgumentError } from '../utils/errors'; import { concatBuffers } from '../utils/other'; import AccountBase from '../account/Base'; import Contract from './Contract'; -import Node from '../Node'; +import Node from '../node/Direct'; import { sendTransaction, SendTransactionOptions, getAccount } from '../chain'; import CompilerBase from './compiler/Base'; diff --git a/src/index-browser.ts b/src/index-browser.ts index 2c4cbc30cf..b73993d965 100644 --- a/src/index-browser.ts +++ b/src/index-browser.ts @@ -61,7 +61,7 @@ export { default as AeSdkBase } from './AeSdkBase'; export { default as AeSdk } from './AeSdk'; export { default as AeSdkAepp } from './AeSdkAepp'; export { default as AeSdkWallet } from './AeSdkWallet'; -export { default as Node } from './Node'; +export { default as Node } from './node/Direct'; export { default as verifyTransaction } from './tx/validator'; export { default as AccountBase } from './account/Base'; export { default as MemoryAccount } from './account/Memory'; diff --git a/src/Node.ts b/src/node/Base.ts similarity index 51% rename from src/Node.ts rename to src/node/Base.ts index 46cab2c9ed..18e044ee1b 100644 --- a/src/Node.ts +++ b/src/node/Base.ts @@ -1,15 +1,9 @@ // eslint-disable-next-line max-classes-per-file import BigNumber from 'bignumber.js'; import { OperationArguments, OperationSpec } from '@azure/core-client'; -import { - genRequestQueuesPolicy, genCombineGetRequestsPolicy, genErrorFormatterPolicy, - genVersionCheckPolicy, genRetryOnFailurePolicy, -} from './utils/autorest'; -import { Node as NodeApi, NodeOptionalParams, ErrorModel } from './apis/node'; -import { mapObject } from './utils/other'; -import { UnsupportedVersionError } from './utils/errors'; -import { Encoded } from './utils/encoder'; -import { ConsensusProtocolVersion } from './tx/builder/constants'; +import { Node as NodeApi } from '../apis/node'; +import { mapObject } from '../utils/other'; +import { Encoded } from '../utils/encoder'; const bigIntPropertyNames = [ 'balance', 'queryFee', 'fee', 'amount', 'nameFee', 'channelAmount', @@ -104,95 +98,5 @@ type NodeTransformedApi = new (...args: ConstructorParameters) = ? NodeApi[Name] : TransformNodeType }; -interface NodeInfo { - url: string; - nodeNetworkId: string; - version: string; - consensusProtocolVersion: ConsensusProtocolVersion; -} - -export default class Node extends (NodeTransformed as unknown as NodeTransformedApi) { - #networkIdPromise?: Promise; - - /** - * @param url - Url for node API - * @param options - Options - * @param options.ignoreVersion - Don't ensure that the node is supported - * @param options.retryCount - Amount of extra requests to do in case of failure - * @param options.retryOverallDelay - Time in ms to wait between all retries - */ - constructor( - url: string, - { - ignoreVersion = false, retryCount = 3, retryOverallDelay = 800, ...options - }: NodeOptionalParams & { - ignoreVersion?: boolean; - retryCount?: number; - retryOverallDelay?: number; - } = {}, - ) { - // eslint-disable-next-line constructor-super - super(url, { - allowInsecureConnection: true, - additionalPolicies: [ - genRequestQueuesPolicy(), - genCombineGetRequestsPolicy(), - genRetryOnFailurePolicy(retryCount, retryOverallDelay), - genErrorFormatterPolicy((body: ErrorModel) => ` ${body.reason}`), - ], - ...options, - }); - if (!ignoreVersion) { - const statusPromise = this.getStatus(); - const versionPromise = statusPromise.then(({ nodeVersion }) => nodeVersion, (error) => error); - this.#networkIdPromise = statusPromise.then(({ networkId }) => networkId, (error) => error); - this.pipeline.addPolicy( - genVersionCheckPolicy('node', '/v3/status', versionPromise, '6.2.0', '7.0.0'), - ); - } - this.intAsString = true; - } - - /** - * Returns network ID provided by node. - * This method won't do extra requests on subsequent calls. - */ - async getNetworkId(): Promise { - this.#networkIdPromise ??= this.getStatus().then(({ networkId }) => networkId); - const networkId = await this.#networkIdPromise; - if (networkId instanceof Error) throw networkId; - return networkId; - } - - async getNodeInfo(): Promise { - const { - nodeVersion, - networkId: nodeNetworkId, - protocols, - topBlockHeight, - } = await this.getStatus(); - - const consensusProtocolVersion = protocols - .filter(({ effectiveAtHeight }) => topBlockHeight >= effectiveAtHeight) - .reduce( - (acc, p) => (p.effectiveAtHeight > acc.effectiveAtHeight ? p : acc), - { effectiveAtHeight: -1, version: 0 }, - ) - .version; - if (ConsensusProtocolVersion[consensusProtocolVersion] == null) { - const version = consensusProtocolVersion.toString(); - const versions = Object.values(ConsensusProtocolVersion) - .filter((el) => typeof el === 'number').map((el) => +el); - const geVersion = Math.min(...versions).toString(); - const ltVersion = (Math.max(...versions) + 1).toString(); - throw new UnsupportedVersionError('consensus protocol', version, geVersion, ltVersion); - } - - return { - url: this.$host, - nodeNetworkId, - version: nodeVersion, - consensusProtocolVersion, - }; - } +export default class NodeBase extends (NodeTransformed as unknown as NodeTransformedApi) { } diff --git a/src/node/Direct.ts b/src/node/Direct.ts new file mode 100644 index 0000000000..ae5db01fe2 --- /dev/null +++ b/src/node/Direct.ts @@ -0,0 +1,101 @@ +import { + genRequestQueuesPolicy, genCombineGetRequestsPolicy, genErrorFormatterPolicy, + genVersionCheckPolicy, genRetryOnFailurePolicy, +} from '../utils/autorest'; +import NodeBase from './Base'; +import { UnsupportedVersionError } from '../utils/errors'; +import { ConsensusProtocolVersion } from '../tx/builder/constants'; +import { NodeOptionalParams, ErrorModel } from '../apis/node'; + +interface NodeInfo { + url: string; + nodeNetworkId: string; + version: string; + consensusProtocolVersion: ConsensusProtocolVersion; +} + +export default class NodeDefault extends NodeBase { + #networkIdPromise?: Promise; + + /** + * @param url - Url for node API + * @param options - Options + * @param options.ignoreVersion - Don't ensure that the node is supported + * @param options.retryCount - Amount of extra requests to do in case of failure + * @param options.retryOverallDelay - Time in ms to wait between all retries + */ + constructor( + url: string, + { + ignoreVersion = false, retryCount = 3, retryOverallDelay = 800, ...options + }: NodeOptionalParams & { + ignoreVersion?: boolean; + retryCount?: number; + retryOverallDelay?: number; + } = {}, + ) { + // eslint-disable-next-line constructor-super + super(url, { + allowInsecureConnection: true, + additionalPolicies: [ + genRequestQueuesPolicy(), + genCombineGetRequestsPolicy(), + genRetryOnFailurePolicy(retryCount, retryOverallDelay), + genErrorFormatterPolicy((body: ErrorModel) => ` ${body.reason}`), + ], + ...options, + }); + if (!ignoreVersion) { + const statusPromise = this.getStatus(); + const versionPromise = statusPromise.then(({ nodeVersion }) => nodeVersion, (error) => error); + this.#networkIdPromise = statusPromise.then(({ networkId }) => networkId, (error) => error); + this.pipeline.addPolicy( + genVersionCheckPolicy('node', '/v3/status', versionPromise, '6.2.0', '7.0.0'), + ); + } + this.intAsString = true; + } + + /** + * Returns network ID provided by node. + * This method won't do extra requests on subsequent calls. + */ + async getNetworkId(): Promise { + this.#networkIdPromise ??= this.getStatus().then(({ networkId }) => networkId); + const networkId = await this.#networkIdPromise; + if (networkId instanceof Error) throw networkId; + return networkId; + } + + async getNodeInfo(): Promise { + const { + nodeVersion, + networkId: nodeNetworkId, + protocols, + topBlockHeight, + } = await this.getStatus(); + + const consensusProtocolVersion = protocols + .filter(({ effectiveAtHeight }) => topBlockHeight >= effectiveAtHeight) + .reduce( + (acc, p) => (p.effectiveAtHeight > acc.effectiveAtHeight ? p : acc), + { effectiveAtHeight: -1, version: 0 }, + ) + .version; + if (ConsensusProtocolVersion[consensusProtocolVersion] == null) { + const version = consensusProtocolVersion.toString(); + const versions = Object.values(ConsensusProtocolVersion) + .filter((el) => typeof el === 'number').map((el) => +el); + const geVersion = Math.min(...versions).toString(); + const ltVersion = (Math.max(...versions) + 1).toString(); + throw new UnsupportedVersionError('consensus protocol', version, geVersion, ltVersion); + } + + return { + url: this.$host, + nodeNetworkId, + version: nodeVersion, + consensusProtocolVersion, + }; + } +} diff --git a/src/oracle.ts b/src/oracle.ts index 6d400ed1f6..2d0ede4f97 100644 --- a/src/oracle.ts +++ b/src/oracle.ts @@ -17,7 +17,7 @@ import { import { _getPollInterval, getHeight, sendTransaction, SendTransactionOptions, } from './chain'; -import Node from './Node'; +import Node from './node/Direct'; import AccountBase from './account/Base'; type OracleQueries = Awaited>['oracleQueries']; diff --git a/src/tx/builder/field-types/abi-version.ts b/src/tx/builder/field-types/abi-version.ts index 50438deb65..671b6b3a79 100644 --- a/src/tx/builder/field-types/abi-version.ts +++ b/src/tx/builder/field-types/abi-version.ts @@ -1,6 +1,6 @@ import { Tag, ConsensusProtocolVersion, AbiVersion } from '../constants'; import { getProtocolDetails } from './ct-version'; -import Node from '../../../Node'; +import Node from '../../../node/Direct'; export default { _getProtocolDetails(c: ConsensusProtocolVersion, tag: Tag): AbiVersion { diff --git a/src/tx/builder/field-types/ct-version.ts b/src/tx/builder/field-types/ct-version.ts index c466445038..e1b21eabce 100644 --- a/src/tx/builder/field-types/ct-version.ts +++ b/src/tx/builder/field-types/ct-version.ts @@ -1,5 +1,5 @@ import { ConsensusProtocolVersion, VmVersion, AbiVersion } from '../constants'; -import Node from '../../../Node'; +import Node from '../../../node/Direct'; /* * First abi/vm by default diff --git a/src/tx/builder/field-types/nonce.ts b/src/tx/builder/field-types/nonce.ts index a5d814852f..a72d2e39f8 100644 --- a/src/tx/builder/field-types/nonce.ts +++ b/src/tx/builder/field-types/nonce.ts @@ -1,6 +1,6 @@ import { isAccountNotFoundError } from '../../../utils/other'; import shortUInt from './short-u-int'; -import Node from '../../../Node'; +import Node from '../../../node/Direct'; import { ArgumentError } from '../../../utils/errors'; import { NextNonceStrategy } from '../../../apis/node'; diff --git a/src/tx/builder/field-types/query-fee.ts b/src/tx/builder/field-types/query-fee.ts index 57e4bdeff1..5adaafd586 100644 --- a/src/tx/builder/field-types/query-fee.ts +++ b/src/tx/builder/field-types/query-fee.ts @@ -1,6 +1,6 @@ import coinAmount from './coin-amount'; import { Int } from '../constants'; -import Node from '../../../Node'; +import Node from '../../../node/Direct'; import { Encoded } from '../../../utils/encoder'; import { ArgumentError } from '../../../utils/errors'; diff --git a/src/tx/builder/field-types/ttl.ts b/src/tx/builder/field-types/ttl.ts index 9bb4665c9e..ca68dad94f 100644 --- a/src/tx/builder/field-types/ttl.ts +++ b/src/tx/builder/field-types/ttl.ts @@ -1,5 +1,5 @@ import shortUInt from './short-u-int'; -import Node from '../../../Node'; +import Node from '../../../node/Direct'; import { ArgumentError } from '../../../utils/errors'; /** diff --git a/src/tx/execution-cost.ts b/src/tx/execution-cost.ts index 2b49b50d30..1f777a772a 100644 --- a/src/tx/execution-cost.ts +++ b/src/tx/execution-cost.ts @@ -4,7 +4,7 @@ import { Tag } from './builder/constants'; import { verify } from '../utils/crypto'; import { getBufferToSign } from '../account/Memory'; import { IllegalArgumentError, InternalError, TransactionError } from '../utils/errors'; -import Node from '../Node'; +import Node from '../node/Direct'; import getTransactionSignerAddress from './transaction-signer'; /** diff --git a/src/tx/validator.ts b/src/tx/validator.ts index 2a5099320f..c4a899634b 100644 --- a/src/tx/validator.ts +++ b/src/tx/validator.ts @@ -6,7 +6,8 @@ import { Tag, ConsensusProtocolVersion } from './builder/constants'; import { buildTx, unpackTx } from './builder'; import { concatBuffers, isAccountNotFoundError } from '../utils/other'; import { Encoded, decode } from '../utils/encoder'; -import Node, { TransformNodeType } from '../Node'; +import { TransformNodeType } from '../node/Base'; +import Node from '../node/Direct'; import { Account } from '../apis/node'; import { genAggressiveCacheGetResponsesPolicy } from '../utils/autorest'; import { UnexpectedTsError } from '../utils/errors';