Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: return DispatchError in dry-run endpoint #1533

Merged
merged 2 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/services/test-helpers/mock/mockAssetHubWestendApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand Down Expand Up @@ -147,12 +148,19 @@ const runtimeDryRun = assetHubWestendRegistryV9435.createType(
mockDryRunCallResult,
);

const runtimeDryRunError = assetHubWestendRegistryV9435.createType(
'Result<CallDryRunEffects, XcmDryRunApiError>',
mockDryRunCallError,
);

export const assetHubWestendQueryInfoCall = (
_extrinsic: GenericExtrinsic,
_length: Uint8Array,
): Promise<RuntimeDispatchInfo> => 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<RuntimeDispatchInfo> =>
Promise.resolve().then(() => runtimeDispatchInfo);
Expand Down Expand Up @@ -220,9 +228,6 @@ export const mockAssetHubWestendApi = {
queryInfo: assetHubWestendQueryInfoCall,
queryFeeDetails,
},
dryRunApi: {
dryRunCall: mockDryRunCall,
},
},
consts: {
system: {
Expand Down
12 changes: 12 additions & 0 deletions src/services/test-helpers/mock/mockDryRunError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const mockDryRunCallError = {
Ok: {
executionResult: {
Err: {
Token: 'NoFunds',
},
},
emittedEvents: [],
localXcm: null,
forwardedXcms: [],
},
};
44 changes: 36 additions & 8 deletions src/services/transaction/TransactionDryRunService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,28 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import type { PostDispatchInfo } from '@polkadot/types/interfaces';
import type { ApiPromise } from '@polkadot/api';
import type { DispatchError, PostDispatchInfo } from '@polkadot/types/interfaces';

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,
Expand All @@ -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,
Expand All @@ -57,13 +68,30 @@ describe('TransactionDryRunService', () => {
const callTx =
'0x1f0801010100411f0100010100c224aad9c6f3bbd784120e9fceee5bfd22a62c69144ee673f76d6a34d280de160104000002043205040091010000000000' as `0x${string}`;

const executionResult = await new TransactionDryRunService(mockAssetHubWestendApi).dryRuntExtrinsic(
sendersAddress,
callTx,
);
const executionResult = await new TransactionDryRunService(mockAHWApi).dryRuntExtrinsic(sendersAddress, callTx);

expect(executionResult?.at.hash).toEqual('');
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);
});
});
14 changes: 10 additions & 4 deletions src/services/transaction/TransactionDryRunService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 5 additions & 5 deletions src/test-helpers/registries/assetHubWestendRegistry.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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', {
Expand All @@ -34,14 +34,14 @@ 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;
}

/**
* Asset Hub Westend v9435 TypeRegistry.
*/
export const assetHubWestendRegistryV9435 = createAssetHubWestendRegistry();
export const assetHubWestendRegistryV9435 = createAssetHubWestendRegistry(9435, assetHubWestendMetadataRpcV9435);
4 changes: 2 additions & 2 deletions src/types/responses/TransactionDryRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -32,7 +32,7 @@ export enum ValidityErrorType {
export interface ITransactionDryRun {
at: IAt;
result: {
resultType: TransactionResultType;
resultType: TransactionResultType | ValidityErrorType;
result: PostDispatchInfo | XcmDryRunApiError | DispatchError;
};
}
Loading