From 801276637e8809ee1ad53cb70710385d01598ad7 Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Tue, 20 Feb 2024 09:31:27 +0100 Subject: [PATCH 1/6] ALL-4863: doge getblock verbose param is boolean --- src/dto/Network.ts | 13 +- src/dto/rpc/DogeRpcSuite.ts | 47 +++++++ src/dto/rpc/index.ts | 1 + src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts | 11 +- src/e2e/rpc/utxo/utxo.e2e.utils.ts | 4 +- src/service/rpc/utxo/AbstractDogeRpc.ts | 130 ++++++++++++++++++++ src/service/rpc/utxo/DogeLoadBalancedRpc.ts | 44 +++++++ src/service/rpc/utxo/DogeRpc.ts | 42 +++++++ src/service/rpc/utxo/index.ts | 1 + src/service/tatum/tatum.utxo.ts | 22 +++- src/util/util.shared.ts | 7 +- 11 files changed, 310 insertions(+), 12 deletions(-) create mode 100644 src/dto/rpc/DogeRpcSuite.ts create mode 100644 src/service/rpc/utxo/AbstractDogeRpc.ts create mode 100644 src/service/rpc/utxo/DogeLoadBalancedRpc.ts create mode 100644 src/service/rpc/utxo/DogeRpc.ts diff --git a/src/dto/Network.ts b/src/dto/Network.ts index 5152c3dd1b..538e7d1013 100644 --- a/src/dto/Network.ts +++ b/src/dto/Network.ts @@ -160,11 +160,11 @@ export const UTXO_BASED_NETWORKS = [ Network.LITECOIN, Network.LITECOIN_TESTNET, Network.ZCASH, - Network.ZCASH_TESTNET, - Network.DOGECOIN, - Network.DOGECOIN_TESTNET, + Network.ZCASH_TESTNET ] +export const DOGECOIN_NETWORKS = [Network.DOGECOIN, Network.DOGECOIN_TESTNET] + export const UTXO_LOAD_BALANCER_ESTIMATE_FEE_NETWORKS = [Network.BITCOIN_CASH] export const UTXO_ESTIMATE_FEE_NETWORKS = [Network.BITCOIN_CASH_TESTNET] @@ -200,12 +200,12 @@ export const UTXO_LOAD_BALANCER_NETWORKS = [ Network.BITCOIN_TESTNET, Network.LITECOIN, Network.LITECOIN_TESTNET, - Network.DOGECOIN, - Network.DOGECOIN_TESTNET, Network.ZCASH, Network.BITCOIN_CASH, ] +export const DOGECOIN_LOAD_BALANCED_NETWORKS = [Network.DOGECOIN, Network.DOGECOIN_TESTNET] + export const EVM_LOAD_BALANCER_NETWORKS = [ Network.FLARE, Network.FLARE_COSTON, @@ -246,6 +246,7 @@ export const STELLAR_LOAD_BALANCER_NETWORKS = [Network.STELLAR] export const LOAD_BALANCER_NETWORKS = [ ...UTXO_LOAD_BALANCER_NETWORKS, + ...DOGECOIN_LOAD_BALANCED_NETWORKS, ...EVM_LOAD_BALANCER_NETWORKS, ...TRON_LOAD_BALANCER_NETWORKS, ...EOS_LOAD_BALANCER_NETWORKS, @@ -286,6 +287,8 @@ export const isUtxoBasedNetwork = (network: Network) => UTXO_BASED_NETWORKS.incl export const isUtxoLoadBalancerEstimateFeeNetwork = (network: Network) => UTXO_LOAD_BALANCER_ESTIMATE_FEE_NETWORKS.includes(network) +export const isDogecoinLoadBalancedNetwork = (network: Network) => DOGECOIN_LOAD_BALANCED_NETWORKS.includes(network) + export const isUtxoEstimateFeeNetwork = (network: Network) => UTXO_ESTIMATE_FEE_NETWORKS.includes(network) export const isUtxoLoadBalancerNetwork = (network: Network) => UTXO_LOAD_BALANCER_NETWORKS.includes(network) diff --git a/src/dto/rpc/DogeRpcSuite.ts b/src/dto/rpc/DogeRpcSuite.ts new file mode 100644 index 0000000000..5f5d8e62aa --- /dev/null +++ b/src/dto/rpc/DogeRpcSuite.ts @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { JsonRpcResponse } from '../JsonRpcResponse.dto' +import { AbstractRpcInterface } from './AbstractJsonRpcInterface' + +export interface DogeRpcSuite extends DogeRpcInterface, AbstractRpcInterface {} + +export interface DogeRpcInterface { + // blockchain methods + getBestBlockHash(): Promise> + getBlock(hashOrHeight: string, verbose?: boolean): Promise> + getBlockChainInfo(): Promise> + getBlockCount(): Promise> + getBlockHash(height: number): Promise> + getBlockHeader(hash: string, verbose?: boolean): Promise> + getBlockStats(hash: string): Promise> + getChainTips(): Promise> + getDifficulty(): Promise> + getMempoolAncestors(txId: string, verbose?: boolean): Promise> + getMempoolDescendants(txId: string, verbose?: boolean): Promise> + getMempoolEntry(txId: string): Promise> + getMempoolInfo(): Promise> + getRawMemPool(verbose?: boolean): Promise> + getTxOut(txId: string, index: number, includeMempool?: boolean): Promise> + getTxOutProof(txIds: string[], blockhash?: string): Promise> + verifyTxOutProof(proof: string): Promise> + + // raw transactions methods + createRawTransaction( + inputs: any[], + outputs: any, + locktime?: number, + replaceable?: boolean, + ): Promise> + decodeRawTransaction(hexstring: string): Promise> + decodeScript(hexstring: string): Promise> + getRawTransaction(txId: string, verbose?: boolean): Promise> + sendRawTransaction(hexstring: string): Promise> + + // utility methods + estimateSmartFee( + blocks: number, + estimateMode?: 'UNSET' | 'ECONOMICAL' | 'CONSERVATIVE', + ): Promise> + validateAddress(address: string): Promise> + verifyMessage(address: string, signature: string, message: string): Promise> +} diff --git a/src/dto/rpc/index.ts b/src/dto/rpc/index.ts index c27408cfce..d2d9f2b264 100644 --- a/src/dto/rpc/index.ts +++ b/src/dto/rpc/index.ts @@ -4,3 +4,4 @@ export * from './TezosRpcSuite' export * from './TronRpcSuite' export * from './UtxoBasedRpcSuite' export * from './XrpRpcSuite' +export * from './DogeRpcSuite' diff --git a/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts b/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts index dfa448294d..e11ec61661 100644 --- a/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts +++ b/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts @@ -1,10 +1,10 @@ -import { Network } from '../../../service' +import { Dogecoin, Network } from '../../../service' import { UtxoE2eUtils, UtxoNetworkType } from './utxo.e2e.utils' describe('Doge', () => { describe('mainnet', () => { it('createrawtransaction', async () => { - const tatum = await UtxoE2eUtils.initTatum({ network: Network.DOGECOIN, type: UtxoNetworkType.MAIN }) + const tatum = await UtxoE2eUtils.initTatum({ network: Network.DOGECOIN, type: UtxoNetworkType.MAIN }) const result = await tatum.rpc.createRawTransaction( [ { @@ -20,5 +20,12 @@ describe('Doge', () => { expect(result.result).not.toBeNull() await tatum.destroy() }) + + it('getblock', async () => { + const tatum = await UtxoE2eUtils.initTatum({ network: Network.DOGECOIN, type: UtxoNetworkType.MAIN }) + await tatum.rpc.getBlock('doge10101010', true) + + await tatum.destroy() + }) }) }) diff --git a/src/e2e/rpc/utxo/utxo.e2e.utils.ts b/src/e2e/rpc/utxo/utxo.e2e.utils.ts index 3a63aa79f4..4a1b108246 100644 --- a/src/e2e/rpc/utxo/utxo.e2e.utils.ts +++ b/src/e2e/rpc/utxo/utxo.e2e.utils.ts @@ -1,5 +1,5 @@ import { Network } from '../../../dto' -import { BaseUtxo, TatumSDK } from '../../../service' +import { BaseUtxo, Dogecoin, TatumSDK } from '../../../service' import { RpcE2eUtils } from '../rpc.e2e.utils' export enum UtxoNetworkType { @@ -15,7 +15,7 @@ interface TatumBtcUtils { } export const UtxoE2eUtils = { - initTatum: async (params: TatumBtcUtils) => + initTatum: async (params: TatumBtcUtils) => TatumSDK.init(RpcE2eUtils.initConfig(params.network, params.apiKey)), e2e: (params: TatumBtcUtils) => { const { type } = params diff --git a/src/service/rpc/utxo/AbstractDogeRpc.ts b/src/service/rpc/utxo/AbstractDogeRpc.ts new file mode 100644 index 0000000000..363de527d0 --- /dev/null +++ b/src/service/rpc/utxo/AbstractDogeRpc.ts @@ -0,0 +1,130 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { DogeRpcInterface, JsonRpcResponse } from '../../../dto' + +export abstract class AbstractDogeRpc implements DogeRpcInterface { + protected abstract rpcCall(method: string, params?: unknown[]): Promise + + async createRawTransaction( + inputs: any[], + outputs: any, + locktime: number, + replaceable: boolean, + ): Promise> { + const params: unknown[] = [inputs, outputs] + if (locktime) { + params.push(locktime) + } + if (replaceable) { + params.push(replaceable) + } + return this.rpcCall>('createrawtransaction', params) + } + + async decodeRawTransaction(hexstring: string): Promise> { + return this.rpcCall>('decoderawtransaction', [hexstring]) + } + + async decodeScript(hexstring: string): Promise> { + return this.rpcCall>('decodescript', [hexstring]) + } + + async estimateSmartFee(blocks: number, estimateMode?: string): Promise> { + const params: unknown[] = [blocks] + if (estimateMode) { + params.push(estimateMode) + } + return this.rpcCall>('estimatesmartfee', params) + } + + async getBestBlockHash(): Promise> { + return this.rpcCall>('getbestblockhash') + } + + async getBlock(hashOrHeight: string, verbose = true): Promise> { + return this.rpcCall>('getblock', [hashOrHeight, verbose]) + } + + async getBlockChainInfo(): Promise> { + return this.rpcCall>('getblockchaininfo') + } + + async getBlockCount(): Promise> { + return this.rpcCall>('getblockcount') + } + + async getBlockHash(height: number): Promise> { + return this.rpcCall>('getblockhash', [height]) + } + + async getBlockHeader(hash: string, verbose = true): Promise> { + return this.rpcCall>('getblockheader', [hash, verbose]) + } + + async getBlockStats(hash: string): Promise> { + return this.rpcCall>('getblockstats', [hash]) + } + + async getChainTips(): Promise> { + return this.rpcCall>('getchaintips') + } + + async getDifficulty(): Promise> { + return this.rpcCall>('getdifficulty') + } + + async getMempoolAncestors(txId: string, verbose = false): Promise> { + return this.rpcCall>('getmempoolancestors', [txId, verbose]) + } + + async getMempoolDescendants(txId: string, verbose = false): Promise> { + return this.rpcCall>('getmempooldescendants', [txId, verbose]) + } + + async getMempoolEntry(txId: string): Promise> { + return this.rpcCall>('getmempoolentry', [txId]) + } + + async getMempoolInfo(): Promise> { + return this.rpcCall>('getmempoolinfo') + } + + async getRawMemPool(verbose = false): Promise> { + return this.rpcCall>('getrawmempool', [verbose]) + } + + async getRawTransaction(txId: string, verbose = false): Promise> { + return this.rpcCall>('getrawtransaction', [txId, verbose]) + } + + async getTxOut(txId: string, index: number, includeMempool = true): Promise> { + return this.rpcCall>('gettxout', [txId, index, includeMempool]) + } + + async getTxOutProof(txIds: string[], blockhash?: string): Promise> { + const params: unknown[] = [txIds] + if (blockhash) { + params.push(blockhash) + } + return this.rpcCall>('gettxoutproof', params) + } + + async sendRawTransaction(hexstring: string): Promise> { + return this.rpcCall>('sendrawtransaction', [hexstring]) + } + + async validateAddress(address: string): Promise> { + return this.rpcCall>('validateaddress', [address]) + } + + async verifyMessage( + address: string, + signature: string, + message: string, + ): Promise> { + return this.rpcCall>('verifymessage', [address, signature, message]) + } + + async verifyTxOutProof(proof: string): Promise> { + return this.rpcCall>('verifytxoutproof', [proof]) + } +} diff --git a/src/service/rpc/utxo/DogeLoadBalancedRpc.ts b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts new file mode 100644 index 0000000000..c5ab20bb67 --- /dev/null +++ b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Container, Service } from 'typedi' +import { JsonRpcCall, JsonRpcResponse, DogeRpcSuite } from '../../../dto' +import { Utils } from '../../../util' +import { AbstractDogeRpc } from './AbstractDogeRpc' +// Need to import like this to keep browser working +import { LoadBalancer } from '../generic/LoadBalancer' + + +@Service({ + factory: (data: { id: string }) => { + return new DogeLoadBalancedRpc(data.id) + }, + transient: true, +}) +export class DogeLoadBalancedRpc extends AbstractDogeRpc implements DogeRpcSuite { + protected readonly loadBalancer: LoadBalancer + + constructor(id: string) { + super() + this.loadBalancer = Container.of(id).get(LoadBalancer) + } + + protected async rpcCall(method: string, params?: unknown[]): Promise { + const preparedCall = Utils.prepareRpcCall(method, params) + return (await this.loadBalancer.rawRpcCall(preparedCall)) as T + } + + async rawRpcCall(body: JsonRpcCall): Promise> { + return this.loadBalancer.rawRpcCall(body) + } + + rawBatchRpcCall(body: JsonRpcCall[]): Promise[] | JsonRpcResponse> { + return this.loadBalancer.rawBatchRpcCall(body) + } + + public destroy() { + this.loadBalancer.destroy() + } + + getRpcNodeUrl(): string { + return this.loadBalancer.getActiveNormalUrlWithFallback().url + } +} diff --git a/src/service/rpc/utxo/DogeRpc.ts b/src/service/rpc/utxo/DogeRpc.ts new file mode 100644 index 0000000000..326914fc63 --- /dev/null +++ b/src/service/rpc/utxo/DogeRpc.ts @@ -0,0 +1,42 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Container, Service } from 'typedi' +import { JsonRpcCall, JsonRpcResponse, DogeRpcSuite } from '../../../dto' +import { Utils } from '../../../util' +import { GenericRpc } from '../generic' +import { AbstractDogeRpc } from './AbstractDogeRpc' + +@Service({ + factory: (data: { id: string }) => { + return new DogeRpc(data.id) + }, + transient: true, +}) +export class DogeRpc extends AbstractDogeRpc implements DogeRpcSuite { + public readonly genericRpc: GenericRpc + + constructor(id: string) { + super() + this.genericRpc = Container.of(id).get(GenericRpc) + } + + protected async rpcCall(method: string, params?: unknown[]): Promise { + const preparedCall = Utils.prepareRpcCall(method, params) + return (await this.genericRpc.rawRpcCall(preparedCall)) as T + } + + async rawBatchRpcCall(body: JsonRpcCall[]): Promise[] | JsonRpcResponse> { + return this.genericRpc.rawBatchRpcCall(body) + } + + async rawRpcCall(body: JsonRpcCall): Promise { + return (await this.genericRpc.rawRpcCall(body)) as T + } + + destroy(): void { + // do nothing + } + + getRpcNodeUrl(): string { + return this.genericRpc.getRpcNodeUrl() + } +} diff --git a/src/service/rpc/utxo/index.ts b/src/service/rpc/utxo/index.ts index c78cf7ad7d..a331bff390 100644 --- a/src/service/rpc/utxo/index.ts +++ b/src/service/rpc/utxo/index.ts @@ -1,2 +1,3 @@ export * from './AbstractUtxoRpc' export * from './UtxoRpc' +export * from './DogeRpc' diff --git a/src/service/tatum/tatum.utxo.ts b/src/service/tatum/tatum.utxo.ts index 2c3fcc4ae9..c744956588 100644 --- a/src/service/tatum/tatum.utxo.ts +++ b/src/service/tatum/tatum.utxo.ts @@ -1,5 +1,5 @@ import { Container } from 'typedi' -import { UtxoBasedRpcSuite, UtxoBasedRpcSuiteEstimateFee } from '../../dto' +import { UtxoBasedRpcSuite, UtxoBasedRpcSuiteEstimateFee, DogeRpcSuite } from '../../dto' import { CONFIG, Utils } from '../../util' import { Address } from '../address' import { FeeUtxo } from '../fee' @@ -48,7 +48,6 @@ export abstract class FullUtxo extends NotificationUtxo { export class Bitcoin extends FullUtxo {} export class Litecoin extends FullUtxo {} -export class Dogecoin extends FullUtxo {} export class BitcoinCash extends NotificationUtxo { rpc: UtxoBasedRpcSuiteEstimateFee @@ -58,3 +57,22 @@ export class BitcoinCash extends NotificationUtxo { } } export class ZCash extends BaseUtxo {} + +export class Dogecoin extends TatumSdkChain{ + rpc: DogeRpcSuite + ipfs: Ipfs + rates: Rates + fee: FeeUtxo + notification: Notification + address: Address + + constructor(id: string) { + super(id) + this.rpc = Utils.getRpc(id, Container.of(id).get(CONFIG)) + this.ipfs = Container.of(id).get(Ipfs) + this.rates = Container.of(id).get(Rates) + this.fee = Container.of(id).get(FeeUtxo) + this.notification = Container.of(id).get(Notification) + this.address = Container.of(id).get(Address) + } +} diff --git a/src/util/util.shared.ts b/src/util/util.shared.ts index caae1da811..7bf885bcc9 100644 --- a/src/util/util.shared.ts +++ b/src/util/util.shared.ts @@ -7,7 +7,7 @@ import { isAlgorandAlgodNetwork, isAlgorandIndexerNetwork, isBnbLoadBalancerNetwork, - isCardanoNetwork, + isCardanoNetwork, isDogecoinLoadBalancedNetwork, isEosLoadBalancerNetwork, isEosNetwork, isEvmArchiveNonArchiveBeaconLoadBalancerNetwork, @@ -104,6 +104,7 @@ import { UtxoLoadBalancerRpcEstimateFee } from '../service/rpc/utxo/UtxoLoadBala import { UtxoRpcEstimateFee } from '../service/rpc/utxo/UtxoRpcEstimateFee' import { Constant } from './constant' import { CONFIG, LOGGER } from './di.tokens' +import { DogeLoadBalancedRpc } from '../service/rpc/utxo/DogeLoadBalancedRpc' export const Utils = { getRpc: (id: string, config: TatumConfig): T => { @@ -137,6 +138,10 @@ export const Utils = { return Container.of(id).get(BnbLoadBalancerRpc) as T } + if (isDogecoinLoadBalancedNetwork(network)) { + return Container.of(id).get(DogeLoadBalancedRpc) as T + } + if (isUtxoLoadBalancerEstimateFeeNetwork(network)) { return Container.of(id).get(UtxoLoadBalancerRpcEstimateFee) as T } From 3f5152b1c5508d018d32e37bae46c49e416eae4f Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Tue, 20 Feb 2024 09:35:16 +0100 Subject: [PATCH 2/6] ALL-4863: removed unused const --- src/dto/Network.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dto/Network.ts b/src/dto/Network.ts index 538e7d1013..921bb1d841 100644 --- a/src/dto/Network.ts +++ b/src/dto/Network.ts @@ -163,8 +163,6 @@ export const UTXO_BASED_NETWORKS = [ Network.ZCASH_TESTNET ] -export const DOGECOIN_NETWORKS = [Network.DOGECOIN, Network.DOGECOIN_TESTNET] - export const UTXO_LOAD_BALANCER_ESTIMATE_FEE_NETWORKS = [Network.BITCOIN_CASH] export const UTXO_ESTIMATE_FEE_NETWORKS = [Network.BITCOIN_CASH_TESTNET] From 0c825a8651df388d350d0079bb712ce9315bf1ea Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Tue, 20 Feb 2024 09:42:08 +0100 Subject: [PATCH 3/6] ALL-4863: version bump and changelog update --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b2990a38c..707d46caa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [4.2.10] - 2024.2.20 + +### Fixed + +- Fixed the `getBlock` method for Doge, addressing an issue with the second boolean parameter. + ## [4.2.9] - 2024.2.15 ### Added diff --git a/package.json b/package.json index 196633748e..0553b1c216 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tatumio/tatum", - "version": "4.2.9", + "version": "4.2.10", "description": "Tatum JS SDK", "author": "Tatum", "repository": "https://github.com/tatumio/tatum-js", From 0f957f04c04cf52dbe27c3dcbc69613f75591d3e Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Tue, 20 Feb 2024 10:05:59 +0100 Subject: [PATCH 4/6] ALL-4863: avoid copying, inherit common rpc methods --- .gitignore | 2 + src/dto/rpc/DogeRpcSuite.ts | 40 +----- src/dto/rpc/UtxoBasedRpcSuite.ts | 7 +- ...actDogeRpc.ts => AbstractCommonUtxoRpc.ts} | 8 +- src/service/rpc/utxo/AbstractUtxoRpc.ts | 123 +----------------- src/service/rpc/utxo/DogeLoadBalancedRpc.ts | 8 +- src/service/rpc/utxo/DogeRpc.ts | 42 ------ src/service/rpc/utxo/index.ts | 1 - 8 files changed, 19 insertions(+), 212 deletions(-) rename src/service/rpc/utxo/{AbstractDogeRpc.ts => AbstractCommonUtxoRpc.ts} (93%) delete mode 100644 src/service/rpc/utxo/DogeRpc.ts diff --git a/.gitignore b/.gitignore index c8b2911d90..c6ea0f0c47 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ coverage *.log .env + +jest-junit.xml diff --git a/src/dto/rpc/DogeRpcSuite.ts b/src/dto/rpc/DogeRpcSuite.ts index 5f5d8e62aa..eb908ec2d6 100644 --- a/src/dto/rpc/DogeRpcSuite.ts +++ b/src/dto/rpc/DogeRpcSuite.ts @@ -2,46 +2,10 @@ import { JsonRpcResponse } from '../JsonRpcResponse.dto' import { AbstractRpcInterface } from './AbstractJsonRpcInterface' +import { UtxoBasedCommonRpcInterface } from './UtxoBasedRpcSuite' export interface DogeRpcSuite extends DogeRpcInterface, AbstractRpcInterface {} -export interface DogeRpcInterface { - // blockchain methods - getBestBlockHash(): Promise> +export interface DogeRpcInterface extends UtxoBasedCommonRpcInterface{ getBlock(hashOrHeight: string, verbose?: boolean): Promise> - getBlockChainInfo(): Promise> - getBlockCount(): Promise> - getBlockHash(height: number): Promise> - getBlockHeader(hash: string, verbose?: boolean): Promise> - getBlockStats(hash: string): Promise> - getChainTips(): Promise> - getDifficulty(): Promise> - getMempoolAncestors(txId: string, verbose?: boolean): Promise> - getMempoolDescendants(txId: string, verbose?: boolean): Promise> - getMempoolEntry(txId: string): Promise> - getMempoolInfo(): Promise> - getRawMemPool(verbose?: boolean): Promise> - getTxOut(txId: string, index: number, includeMempool?: boolean): Promise> - getTxOutProof(txIds: string[], blockhash?: string): Promise> - verifyTxOutProof(proof: string): Promise> - - // raw transactions methods - createRawTransaction( - inputs: any[], - outputs: any, - locktime?: number, - replaceable?: boolean, - ): Promise> - decodeRawTransaction(hexstring: string): Promise> - decodeScript(hexstring: string): Promise> - getRawTransaction(txId: string, verbose?: boolean): Promise> - sendRawTransaction(hexstring: string): Promise> - - // utility methods - estimateSmartFee( - blocks: number, - estimateMode?: 'UNSET' | 'ECONOMICAL' | 'CONSERVATIVE', - ): Promise> - validateAddress(address: string): Promise> - verifyMessage(address: string, signature: string, message: string): Promise> } diff --git a/src/dto/rpc/UtxoBasedRpcSuite.ts b/src/dto/rpc/UtxoBasedRpcSuite.ts index 48e6872d80..86be8437ce 100644 --- a/src/dto/rpc/UtxoBasedRpcSuite.ts +++ b/src/dto/rpc/UtxoBasedRpcSuite.ts @@ -5,10 +5,9 @@ import { AbstractRpcInterface } from './AbstractJsonRpcInterface' export interface UtxoBasedRpcSuite extends UtxoBasedRpcInterface, AbstractRpcInterface {} -export interface UtxoBasedRpcInterface { +export interface UtxoBasedCommonRpcInterface { // blockchain methods getBestBlockHash(): Promise> - getBlock(hashOrHeight: string, verbose?: 0 | 1 | 2): Promise> getBlockChainInfo(): Promise> getBlockCount(): Promise> getBlockHash(height: number): Promise> @@ -46,6 +45,10 @@ export interface UtxoBasedRpcInterface { verifyMessage(address: string, signature: string, message: string): Promise> } +export interface UtxoBasedRpcInterface extends UtxoBasedCommonRpcInterface{ + getBlock(hashOrHeight: string, verbose?: 0 | 1 | 2): Promise> +} + export interface UtxoBasedRpcInterfaceEstimateFee extends UtxoBasedRpcInterface { estimateFee(): Promise> } diff --git a/src/service/rpc/utxo/AbstractDogeRpc.ts b/src/service/rpc/utxo/AbstractCommonUtxoRpc.ts similarity index 93% rename from src/service/rpc/utxo/AbstractDogeRpc.ts rename to src/service/rpc/utxo/AbstractCommonUtxoRpc.ts index 363de527d0..28e9208405 100644 --- a/src/service/rpc/utxo/AbstractDogeRpc.ts +++ b/src/service/rpc/utxo/AbstractCommonUtxoRpc.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { DogeRpcInterface, JsonRpcResponse } from '../../../dto' +import { JsonRpcResponse, UtxoBasedCommonRpcInterface } from '../../../dto' -export abstract class AbstractDogeRpc implements DogeRpcInterface { +export abstract class AbstractCommonUtxoRpc implements UtxoBasedCommonRpcInterface { protected abstract rpcCall(method: string, params?: unknown[]): Promise async createRawTransaction( @@ -40,10 +40,6 @@ export abstract class AbstractDogeRpc implements DogeRpcInterface { return this.rpcCall>('getbestblockhash') } - async getBlock(hashOrHeight: string, verbose = true): Promise> { - return this.rpcCall>('getblock', [hashOrHeight, verbose]) - } - async getBlockChainInfo(): Promise> { return this.rpcCall>('getblockchaininfo') } diff --git a/src/service/rpc/utxo/AbstractUtxoRpc.ts b/src/service/rpc/utxo/AbstractUtxoRpc.ts index e697c320a6..9158132ab4 100644 --- a/src/service/rpc/utxo/AbstractUtxoRpc.ts +++ b/src/service/rpc/utxo/AbstractUtxoRpc.ts @@ -1,130 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { JsonRpcResponse, UtxoBasedRpcInterface } from '../../../dto' +import { AbstractCommonUtxoRpc } from './AbstractCommonUtxoRpc' -export abstract class AbstractUtxoRpc implements UtxoBasedRpcInterface { +export abstract class AbstractUtxoRpc extends AbstractCommonUtxoRpc implements UtxoBasedRpcInterface { protected abstract rpcCall(method: string, params?: unknown[]): Promise - async createRawTransaction( - inputs: any[], - outputs: any, - locktime: number, - replaceable: boolean, - ): Promise> { - const params: unknown[] = [inputs, outputs] - if (locktime) { - params.push(locktime) - } - if (replaceable) { - params.push(replaceable) - } - return this.rpcCall>('createrawtransaction', params) - } - - async decodeRawTransaction(hexstring: string): Promise> { - return this.rpcCall>('decoderawtransaction', [hexstring]) - } - - async decodeScript(hexstring: string): Promise> { - return this.rpcCall>('decodescript', [hexstring]) - } - - async estimateSmartFee(blocks: number, estimateMode?: string): Promise> { - const params: unknown[] = [blocks] - if (estimateMode) { - params.push(estimateMode) - } - return this.rpcCall>('estimatesmartfee', params) - } - - async getBestBlockHash(): Promise> { - return this.rpcCall>('getbestblockhash') - } - async getBlock(hashOrHeight: string, verbose: 0 | 1 | 2 = 1): Promise> { return this.rpcCall>('getblock', [hashOrHeight, verbose]) } - - async getBlockChainInfo(): Promise> { - return this.rpcCall>('getblockchaininfo') - } - - async getBlockCount(): Promise> { - return this.rpcCall>('getblockcount') - } - - async getBlockHash(height: number): Promise> { - return this.rpcCall>('getblockhash', [height]) - } - - async getBlockHeader(hash: string, verbose = true): Promise> { - return this.rpcCall>('getblockheader', [hash, verbose]) - } - - async getBlockStats(hash: string): Promise> { - return this.rpcCall>('getblockstats', [hash]) - } - - async getChainTips(): Promise> { - return this.rpcCall>('getchaintips') - } - - async getDifficulty(): Promise> { - return this.rpcCall>('getdifficulty') - } - - async getMempoolAncestors(txId: string, verbose = false): Promise> { - return this.rpcCall>('getmempoolancestors', [txId, verbose]) - } - - async getMempoolDescendants(txId: string, verbose = false): Promise> { - return this.rpcCall>('getmempooldescendants', [txId, verbose]) - } - - async getMempoolEntry(txId: string): Promise> { - return this.rpcCall>('getmempoolentry', [txId]) - } - - async getMempoolInfo(): Promise> { - return this.rpcCall>('getmempoolinfo') - } - - async getRawMemPool(verbose = false): Promise> { - return this.rpcCall>('getrawmempool', [verbose]) - } - - async getRawTransaction(txId: string, verbose = false): Promise> { - return this.rpcCall>('getrawtransaction', [txId, verbose]) - } - - async getTxOut(txId: string, index: number, includeMempool = true): Promise> { - return this.rpcCall>('gettxout', [txId, index, includeMempool]) - } - - async getTxOutProof(txIds: string[], blockhash?: string): Promise> { - const params: unknown[] = [txIds] - if (blockhash) { - params.push(blockhash) - } - return this.rpcCall>('gettxoutproof', params) - } - - async sendRawTransaction(hexstring: string): Promise> { - return this.rpcCall>('sendrawtransaction', [hexstring]) - } - - async validateAddress(address: string): Promise> { - return this.rpcCall>('validateaddress', [address]) - } - - async verifyMessage( - address: string, - signature: string, - message: string, - ): Promise> { - return this.rpcCall>('verifymessage', [address, signature, message]) - } - - async verifyTxOutProof(proof: string): Promise> { - return this.rpcCall>('verifytxoutproof', [proof]) - } } diff --git a/src/service/rpc/utxo/DogeLoadBalancedRpc.ts b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts index c5ab20bb67..911ab3b19d 100644 --- a/src/service/rpc/utxo/DogeLoadBalancedRpc.ts +++ b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts @@ -2,9 +2,9 @@ import { Container, Service } from 'typedi' import { JsonRpcCall, JsonRpcResponse, DogeRpcSuite } from '../../../dto' import { Utils } from '../../../util' -import { AbstractDogeRpc } from './AbstractDogeRpc' // Need to import like this to keep browser working import { LoadBalancer } from '../generic/LoadBalancer' +import { AbstractCommonUtxoRpc } from './AbstractCommonUtxoRpc' @Service({ @@ -13,7 +13,7 @@ import { LoadBalancer } from '../generic/LoadBalancer' }, transient: true, }) -export class DogeLoadBalancedRpc extends AbstractDogeRpc implements DogeRpcSuite { +export class DogeLoadBalancedRpc extends AbstractCommonUtxoRpc implements DogeRpcSuite { protected readonly loadBalancer: LoadBalancer constructor(id: string) { @@ -41,4 +41,8 @@ export class DogeLoadBalancedRpc extends AbstractDogeRpc implements DogeRpcSuite getRpcNodeUrl(): string { return this.loadBalancer.getActiveNormalUrlWithFallback().url } + + async getBlock(hashOrHeight: string, verbose = true): Promise> { + return this.rpcCall>('getblock', [hashOrHeight, verbose]) + } } diff --git a/src/service/rpc/utxo/DogeRpc.ts b/src/service/rpc/utxo/DogeRpc.ts deleted file mode 100644 index 326914fc63..0000000000 --- a/src/service/rpc/utxo/DogeRpc.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Container, Service } from 'typedi' -import { JsonRpcCall, JsonRpcResponse, DogeRpcSuite } from '../../../dto' -import { Utils } from '../../../util' -import { GenericRpc } from '../generic' -import { AbstractDogeRpc } from './AbstractDogeRpc' - -@Service({ - factory: (data: { id: string }) => { - return new DogeRpc(data.id) - }, - transient: true, -}) -export class DogeRpc extends AbstractDogeRpc implements DogeRpcSuite { - public readonly genericRpc: GenericRpc - - constructor(id: string) { - super() - this.genericRpc = Container.of(id).get(GenericRpc) - } - - protected async rpcCall(method: string, params?: unknown[]): Promise { - const preparedCall = Utils.prepareRpcCall(method, params) - return (await this.genericRpc.rawRpcCall(preparedCall)) as T - } - - async rawBatchRpcCall(body: JsonRpcCall[]): Promise[] | JsonRpcResponse> { - return this.genericRpc.rawBatchRpcCall(body) - } - - async rawRpcCall(body: JsonRpcCall): Promise { - return (await this.genericRpc.rawRpcCall(body)) as T - } - - destroy(): void { - // do nothing - } - - getRpcNodeUrl(): string { - return this.genericRpc.getRpcNodeUrl() - } -} diff --git a/src/service/rpc/utxo/index.ts b/src/service/rpc/utxo/index.ts index a331bff390..c78cf7ad7d 100644 --- a/src/service/rpc/utxo/index.ts +++ b/src/service/rpc/utxo/index.ts @@ -1,3 +1,2 @@ export * from './AbstractUtxoRpc' export * from './UtxoRpc' -export * from './DogeRpc' From c4813eb8646dd3b89a450efa9158d61d61e218f7 Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Tue, 20 Feb 2024 10:23:59 +0100 Subject: [PATCH 5/6] ALL-4863: abstract doge rpc, test fix --- src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts | 24 +++++++++++++++++++-- src/service/rpc/utxo/AbstractDogeRpc.ts | 11 ++++++++++ src/service/rpc/utxo/DogeLoadBalancedRpc.ts | 8 ++----- 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 src/service/rpc/utxo/AbstractDogeRpc.ts diff --git a/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts b/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts index e11ec61661..86547b91cb 100644 --- a/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts +++ b/src/e2e/rpc/utxo/tatum.rpc.doge.spec.ts @@ -22,8 +22,28 @@ describe('Doge', () => { }) it('getblock', async () => { - const tatum = await UtxoE2eUtils.initTatum({ network: Network.DOGECOIN, type: UtxoNetworkType.MAIN }) - await tatum.rpc.getBlock('doge10101010', true) + const tatum = await UtxoE2eUtils.initTatum({ + network: Network.DOGECOIN, + type: UtxoNetworkType.MAIN, + }) + const hash: string = '4cddee0cb7cc1e7a5d6a099285461e0470b2af8078dae35d5ac77e7c57bbc997' + const response1 = await tatum.rpc.getBlock(hash, true) + + expect(response1).toBeDefined() + expect(response1.result).toStrictEqual( + expect.objectContaining({ + hash, + version: 6422788, + height: 5092153, + size: 998443, + merkleroot: '8918a6f70a0ca3c9b4f745c86a7aa3a3d67d18b9c658eacb571c13d7fed0c7a7', + chainwork: '000000000000000000000000000000000000000000000f2239716b279a602583', + }), + ) + + const response2 = await tatum.rpc.getBlock(hash, false) + expect(response2).toBeDefined() + expect(typeof response2.result).toBe('string') await tatum.destroy() }) diff --git a/src/service/rpc/utxo/AbstractDogeRpc.ts b/src/service/rpc/utxo/AbstractDogeRpc.ts new file mode 100644 index 0000000000..bfbb9034e5 --- /dev/null +++ b/src/service/rpc/utxo/AbstractDogeRpc.ts @@ -0,0 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { DogeRpcInterface, JsonRpcResponse } from '../../../dto' +import { AbstractCommonUtxoRpc } from './AbstractCommonUtxoRpc' + +export abstract class AbstractDogeRpc extends AbstractCommonUtxoRpc implements DogeRpcInterface { + protected abstract rpcCall(method: string, params?: unknown[]): Promise + + async getBlock(hashOrHeight: string, verbose = true): Promise> { + return this.rpcCall>('getblock', [hashOrHeight, verbose]) + } +} diff --git a/src/service/rpc/utxo/DogeLoadBalancedRpc.ts b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts index 911ab3b19d..d3cb7fdb63 100644 --- a/src/service/rpc/utxo/DogeLoadBalancedRpc.ts +++ b/src/service/rpc/utxo/DogeLoadBalancedRpc.ts @@ -4,7 +4,7 @@ import { JsonRpcCall, JsonRpcResponse, DogeRpcSuite } from '../../../dto' import { Utils } from '../../../util' // Need to import like this to keep browser working import { LoadBalancer } from '../generic/LoadBalancer' -import { AbstractCommonUtxoRpc } from './AbstractCommonUtxoRpc' +import { AbstractDogeRpc } from './AbstractDogeRpc' @Service({ @@ -13,7 +13,7 @@ import { AbstractCommonUtxoRpc } from './AbstractCommonUtxoRpc' }, transient: true, }) -export class DogeLoadBalancedRpc extends AbstractCommonUtxoRpc implements DogeRpcSuite { +export class DogeLoadBalancedRpc extends AbstractDogeRpc implements DogeRpcSuite { protected readonly loadBalancer: LoadBalancer constructor(id: string) { @@ -41,8 +41,4 @@ export class DogeLoadBalancedRpc extends AbstractCommonUtxoRpc implements DogeRp getRpcNodeUrl(): string { return this.loadBalancer.getActiveNormalUrlWithFallback().url } - - async getBlock(hashOrHeight: string, verbose = true): Promise> { - return this.rpcCall>('getblock', [hashOrHeight, verbose]) - } } From 2548ef2c591e3860439a0d4d4c956e7b690f6159 Mon Sep 17 00:00:00 2001 From: Rostislav Jadavan Date: Thu, 22 Feb 2024 11:56:41 +0100 Subject: [PATCH 6/6] ALL-4863: changelog update (after merge) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cceaa830e1..33d9a166d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [4.2.11] - 2024.2.22 + +### Fixed + +- Fixed the `getBlock` method for Doge, addressing an issue with the second boolean parameter. + ## [4.2.10] - 2024.2.22 ### Fixed diff --git a/package.json b/package.json index 0553b1c216..6e0bd5b0fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tatumio/tatum", - "version": "4.2.10", + "version": "4.2.11", "description": "Tatum JS SDK", "author": "Tatum", "repository": "https://github.com/tatumio/tatum-js",