From 44017f3d90d183dfd005394cf7b337c630000a04 Mon Sep 17 00:00:00 2001 From: Imod7 Date: Mon, 4 Nov 2024 13:36:16 +0100 Subject: [PATCH] fix: return DispatchError in dry-run endpoint --- .../mock/mockAssetHubWestendApi.ts | 13 ++++-- .../test-helpers/mock/mockDryRunError.ts | 12 +++++ .../TransactionDryRunService.spec.ts | 44 ++++++++++++++++--- .../transaction/TransactionDryRunService.ts | 14 ++++-- .../registries/assetHubWestendRegistry.ts | 10 ++--- src/types/responses/TransactionDryRun.ts | 4 +- 6 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 src/services/test-helpers/mock/mockDryRunError.ts diff --git a/src/services/test-helpers/mock/mockAssetHubWestendApi.ts b/src/services/test-helpers/mock/mockAssetHubWestendApi.ts index e9b851c4a..5c9378a2a 100644 --- a/src/services/test-helpers/mock/mockAssetHubWestendApi.ts +++ b/src/services/test-helpers/mock/mockAssetHubWestendApi.ts @@ -39,6 +39,7 @@ import { getMetadata as mockMetaData } from './data/mockNonimationPoolResponseDa import traceBlockRPC from './data/traceBlock.json'; import { defaultMockApi } from './mockApi'; import { mockDryRunCallResult } from './mockDryRunCall'; +import { mockDryRunCallError } from './mockDryRunError'; const chain = () => Promise.resolve().then(() => { @@ -147,12 +148,19 @@ const runtimeDryRun = assetHubWestendRegistryV9435.createType( mockDryRunCallResult, ); +const runtimeDryRunError = assetHubWestendRegistryV9435.createType( + 'Result', + mockDryRunCallError, +); + export const assetHubWestendQueryInfoCall = ( _extrinsic: GenericExtrinsic, _length: Uint8Array, ): Promise => Promise.resolve().then(() => runtimeDispatchInfo); -const mockDryRunCall = () => Promise.resolve().then(() => runtimeDryRun); +export const mockDryRunCall = () => Promise.resolve().then(() => runtimeDryRun); + +export const mockDryRunError = () => Promise.resolve().then(() => runtimeDryRunError); export const assetHubWestendQueryInfoAt = (_extrinsic: string, _hash: Hash): Promise => Promise.resolve().then(() => runtimeDispatchInfo); @@ -220,9 +228,6 @@ export const mockAssetHubWestendApi = { queryInfo: assetHubWestendQueryInfoCall, queryFeeDetails, }, - dryRunApi: { - dryRunCall: mockDryRunCall, - }, }, consts: { system: { diff --git a/src/services/test-helpers/mock/mockDryRunError.ts b/src/services/test-helpers/mock/mockDryRunError.ts new file mode 100644 index 000000000..fd2796a61 --- /dev/null +++ b/src/services/test-helpers/mock/mockDryRunError.ts @@ -0,0 +1,12 @@ +export const mockDryRunCallError = { + Ok: { + executionResult: { + Err: { + Token: 'NoFunds', + } + }, + emittedEvents: [], + localXcm: null, + forwardedXcms: [] + } +}; diff --git a/src/services/transaction/TransactionDryRunService.spec.ts b/src/services/transaction/TransactionDryRunService.spec.ts index b81fa634d..5ed385ab3 100644 --- a/src/services/transaction/TransactionDryRunService.spec.ts +++ b/src/services/transaction/TransactionDryRunService.spec.ts @@ -16,17 +16,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -import type { PostDispatchInfo } from '@polkadot/types/interfaces'; +import type { PostDispatchInfo, DispatchError } from '@polkadot/types/interfaces'; +import type { ApiPromise } from '@polkadot/api'; import { TransactionResultType } from '../../types/responses'; -import { blockHash22887036, mockAssetHubWestendApi } from '../test-helpers/mock'; +import { blockHash22887036, mockAssetHubWestendApi, mockDryRunCall, mockDryRunError } from '../test-helpers/mock'; import { mockDryRunCallResult } from '../test-helpers/mock/mockDryRunCall'; +import { mockDryRunCallError } from '../test-helpers/mock/mockDryRunError'; import { TransactionDryRunService } from './TransactionDryRunService'; +const mockAHWApi = { + ...mockAssetHubWestendApi, + call: { + dryRunApi: { + dryRunCall: mockDryRunCall, + }, + }, +} as unknown as ApiPromise; + describe('TransactionDryRunService', () => { const sendersAddress = '5HBuLJz9LdkUNseUEL6DLeVkx2bqEi6pQr8Ea7fS4bzx7i7E'; it('Should correctly execute a dry run for a submittable executable', async () => { - const executionResult = await new TransactionDryRunService(mockAssetHubWestendApi).dryRuntExtrinsic( + const executionResult = await new TransactionDryRunService(mockAHWApi).dryRuntExtrinsic( sendersAddress, '0xfc041f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de160104000002043205040091010000000000', blockHash22887036, @@ -42,7 +53,7 @@ describe('TransactionDryRunService', () => { const payloadTx: `0x${string}` = '0xf81f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de16010400000204320504009101000000000045022800010000e0510f00040000000000000000000000000000000000000000000000000000000000000000000000be2554aa8a0151eb4d706308c47d16996af391e4c5e499c7cbef24259b7d4503'; - const executionResult = await new TransactionDryRunService(mockAssetHubWestendApi).dryRuntExtrinsic( + const executionResult = await new TransactionDryRunService(mockAHWApi).dryRuntExtrinsic( sendersAddress, payloadTx, blockHash22887036, @@ -57,7 +68,7 @@ describe('TransactionDryRunService', () => { const callTx = '0x1f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de160104000002043205040091010000000000' as `0x${string}`; - const executionResult = await new TransactionDryRunService(mockAssetHubWestendApi).dryRuntExtrinsic( + const executionResult = await new TransactionDryRunService(mockAHWApi).dryRuntExtrinsic( sendersAddress, callTx, ); @@ -66,4 +77,27 @@ describe('TransactionDryRunService', () => { const resData = executionResult?.result.result as PostDispatchInfo; expect(resData.paysFee.toString()).toEqual(mockDryRunCallResult.Ok.executionResult.Ok.paysFee); }); + + it('should correctly execute a dry run for a call and return an error', async () => { + const mockAHWApiErr = { + ...mockAssetHubWestendApi, + call: { + dryRunApi: { + dryRunCall: mockDryRunError, + }, + }, + } as unknown as ApiPromise; + + const callTx = + '0x0a0000fe06fc3db07fb1a4ce89a76eaed1e54519b5940d2652b8d6794ad4ddfcdcb16c0f00d0eca2b99401' as `0x${string}`; + + const executionResult = await new TransactionDryRunService(mockAHWApiErr).dryRuntExtrinsic( + sendersAddress, + callTx, + ); + + expect(executionResult?.at.hash).toEqual(''); + const resData = executionResult?.result.result as DispatchError; + expect(resData.asToken.toString()).toEqual(mockDryRunCallError.Ok.executionResult.Err.Token); + }); }); diff --git a/src/services/transaction/TransactionDryRunService.ts b/src/services/transaction/TransactionDryRunService.ts index cd64d3f3a..e3a3e5263 100644 --- a/src/services/transaction/TransactionDryRunService.ts +++ b/src/services/transaction/TransactionDryRunService.ts @@ -17,7 +17,7 @@ import type { BlockHash, CallDryRunEffects, XcmDryRunApiError } from '@polkadot/types/interfaces'; import type { Result } from '@polkadot/types-codec'; -import { ITransactionDryRun, TransactionResultType } from '../../types/responses'; +import { ITransactionDryRun, TransactionResultType, ValidityErrorType } from '../../types/responses'; import { AbstractService } from '../AbstractService'; import { extractCauseAndStack } from './extractCauseAndStack'; @@ -56,9 +56,15 @@ export class TransactionDryRunService extends AbstractService { }, result: { resultType: response.isOk - ? TransactionResultType.DispatchOutcome - : TransactionResultType.TransactionValidityError, - result: response.isOk ? response.asOk.executionResult.asOk : response.asErr, + ? response.asOk.executionResult.isOk + ? TransactionResultType.DispatchOutcome + : TransactionResultType.DispatchError + : ValidityErrorType.Invalid, + result: response.isOk + ? response.asOk.executionResult.isOk + ? response.asOk.executionResult.asOk + : response.asOk.executionResult.asErr + : response.asErr, }, }; } catch (err) { diff --git a/src/test-helpers/registries/assetHubWestendRegistry.ts b/src/test-helpers/registries/assetHubWestendRegistry.ts index 900fac7b0..2ab6dc321 100644 --- a/src/test-helpers/registries/assetHubWestendRegistry.ts +++ b/src/test-helpers/registries/assetHubWestendRegistry.ts @@ -1,4 +1,4 @@ -// Copyright 2017-2022 Parity Technologies (UK) Ltd. +// Copyright 2017-2024 Parity Technologies (UK) Ltd. // This file is part of Substrate API Sidecar. // // Substrate API Sidecar is free software: you can redistribute it and/or modify @@ -24,7 +24,7 @@ import { assetHubWestendMetadataRpcV9435 } from '../metadata/assetHubWestendMeta * Create a type registry for Asset Hub Westend. * Useful for creating types in order to facilitate testing. */ -function createAssetHubWestendRegistry(): TypeRegistry { +function createAssetHubWestendRegistry(specVersion: number, metadata: `0x${string}`): TypeRegistry { const registry = new TypeRegistry(); registry.setChainProperties( registry.createType('ChainProperties', { @@ -34,9 +34,9 @@ function createAssetHubWestendRegistry(): TypeRegistry { }), ); - registry.register(getSpecTypes(registry, 'westmint', 'westmint', 9435)); + registry.register(getSpecTypes(registry, 'Westend Asset Hub', 'westmint', specVersion)); - registry.setMetadata(new Metadata(registry, assetHubWestendMetadataRpcV9435)); + registry.setMetadata(new Metadata(registry, metadata)); return registry; } @@ -44,4 +44,4 @@ function createAssetHubWestendRegistry(): TypeRegistry { /** * Asset Hub Westend v9435 TypeRegistry. */ -export const assetHubWestendRegistryV9435 = createAssetHubWestendRegistry(); +export const assetHubWestendRegistryV9435 = createAssetHubWestendRegistry(9435, assetHubWestendMetadataRpcV9435); diff --git a/src/types/responses/TransactionDryRun.ts b/src/types/responses/TransactionDryRun.ts index f1fb52f75..626b69183 100644 --- a/src/types/responses/TransactionDryRun.ts +++ b/src/types/responses/TransactionDryRun.ts @@ -20,8 +20,8 @@ import type { DispatchError, PostDispatchInfo, XcmDryRunApiError } from '@polkad import { IAt } from './At'; export enum TransactionResultType { - TransactionValidityError = 'TransactionValidityError', DispatchOutcome = 'DispatchOutcome', + DispatchError = 'DispatchError', } export enum ValidityErrorType { @@ -32,7 +32,7 @@ export enum ValidityErrorType { export interface ITransactionDryRun { at: IAt; result: { - resultType: TransactionResultType; + resultType: TransactionResultType | ValidityErrorType; result: PostDispatchInfo | XcmDryRunApiError | DispatchError; }; }