Skip to content

feat: add explicit handle validation arg #1091

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

Merged
merged 2 commits into from
Feb 12, 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
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,12 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
[ServiceNames.TxSubmit]: async () => {
const txSubmitProvider = args.useSubmitApi
? getSubmitApiProvider()
: await getOgmiosTxSubmitProvider(dnsResolver, logger, args, await getHandleProvider());
: await getOgmiosTxSubmitProvider(
dnsResolver,
logger,
args,
args.submitValidateHandles ? await getHandleProvider() : undefined
);
return new TxSubmitHttpService({ logger, txSubmitProvider });
}
};
Expand Down
4 changes: 3 additions & 1 deletion packages/cardano-services/src/Program/programs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ export enum ProviderServerOptionDescriptions {
UseBlockfrost = 'Enables Blockfrost cached data DB',
UseKoraLabsProvider = 'Use the KoraLabs handle provider',
UseSubmitApi = 'Use cardano-submit-api provider',
UseTypeormAssetProvider = 'Use the TypeORM Asset Provider (default is db-sync)'
UseTypeormAssetProvider = 'Use the TypeORM Asset Provider (default is db-sync)',
SubmitValidateHandles = 'Validate handle resolutions before submitting transactions. Requires handle provider options (USE_KORA_LABS or POSTGRES options with HANDLE suffix).'
}

export type ProviderServerArgs = CommonProgramOptions &
Expand All @@ -82,6 +83,7 @@ export type ProviderServerArgs = CommonProgramOptions &
paginationPageSizeLimit?: number;
serviceNames: ServiceNames[];
submitApiUrl?: URL;
submitValidateHandles?: boolean;
tokenMetadataCacheTTL?: Seconds;
tokenMetadataServerUrl?: string;
tokenMetadataRequestTimeout?: Milliseconds;
Expand Down
12 changes: 12 additions & 0 deletions packages/cardano-services/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,18 @@ addOptions(withOgmiosOptions(withHandlePolicyIdsOptions(providerServerWithCommon
stringOptionToBoolean(useKoraLabs, Programs.ProviderServer, ProviderServerOptionDescriptions.UseKoraLabsProvider),
false
),
newOption(
'--submit-validate-handles <true/false>',
ProviderServerOptionDescriptions.SubmitValidateHandles,
'SUBMIT_VALIDATE_HANDLES',
(submitValidateHandles) =>
stringOptionToBoolean(
submitValidateHandles,
Programs.ProviderServer,
ProviderServerOptionDescriptions.SubmitValidateHandles
),
false
),
newOption(
'--pagination-page-size-limit <paginationPageSizeLimit>',
ProviderServerOptionDescriptions.PaginationPageSizeLimit,
Expand Down
15 changes: 12 additions & 3 deletions packages/cardano-services/test/Program/services/ogmios.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,18 @@ describe('Service dependency abstractions', () => {
});

it('throws a provider error if the submitted transaction does not contain addresses that can be resolved from the included context', async () => {
const provider = await getOgmiosTxSubmitProvider(dnsResolver, logger, {
ogmiosSrvServiceName: process.env.OGMIOS_SRV_SERVICE_NAME
});
const provider = await getOgmiosTxSubmitProvider(
dnsResolver,
logger,
{
ogmiosSrvServiceName: process.env.OGMIOS_SRV_SERVICE_NAME
},
{
getPolicyIds: async () => [],
healthCheck: async () => ({ ok: true }),
resolveHandles: async ({ handles }) => handles.map(() => null)
}
);
await provider.initialize();
await provider.start();

Expand Down
22 changes: 21 additions & 1 deletion packages/cardano-services/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,27 @@ describe('CLI', () => {
await assertServiceHealthy(apiUrl, services.txSubmit, lastBlock, { withTip: false });
});

it('exposes a HTTP server with /tx-submit/health endpoint when SUBMIT_VALIDATE_HANDLES is true', async () => {
proc = withLogging(
fork(exePath, ['start-provider-server'], {
env: {
API_URL: apiUrl,
CARDANO_NODE_CONFIG_PATH: cardanoNodeConfigPath,
DB_CACHE_TTL: dbCacheTtl,
HANDLE_POLICY_IDS,
LOGGER_MIN_SEVERITY: 'error',
OGMIOS_URL: ogmiosConnection.address.webSocket,
POSTGRES_CONNECTION_STRING_HANDLE: postgresConnectionStringHandle,
SERVICE_NAMES: `${ServiceNames.TxSubmit}`,
SUBMIT_VALIDATE_HANDLES: 'true'
},
stdio: 'pipe'
})
);

await assertServiceHealthy(apiUrl, services.txSubmit, lastBlock, { withTip: false });
});

it('tx-submit uses the default Ogmios configuration if not specified when using env variables', async () => {
proc = withLogging(
fork(exePath, ['start-provider-server'], {
Expand All @@ -1494,7 +1515,6 @@ describe('CLI', () => {
HANDLE_POLICY_IDS,
HANDLE_PROVIDER_SERVER_URL,
LOGGER_MIN_SEVERITY: 'error',
POSTGRES_CONNECTION_STRING_HANDLE: postgresConnectionStringHandle,
SERVICE_NAMES: ServiceNames.TxSubmit
},
stdio: 'pipe'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,8 @@ export class OgmiosTxSubmitProvider extends RunnableModule implements TxSubmitPr
private async throwIfHandleResolutionConflict(context: SubmitTxArgs['context']): Promise<void> {
if (context?.handleResolutions && context.handleResolutions.length > 0) {
if (!this.#handleProvider) {
throw new ProviderError(
ProviderFailure.NotImplemented,
undefined,
'No HandleProvider was set during construction.'
);
this.logger.debug('No handle provider: bypassing handle validation');
return;
}

const handleInfoList = await this.#handleProvider.resolveHandles({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,6 @@ describe('OgmiosTxSubmitProvider', () => {
);
});

it('throws an error if context has handles, and no handleProvider is passed', async () => {
mockServer = createMockOgmiosServer({
submitTx: { response: { failWith: { type: 'eraMismatch' }, success: false } }
});
await listenPromise(mockServer, connection.port);
provider = new OgmiosTxSubmitProvider(connection, { logger });
await provider.initialize();
await provider.start();

await expect(
provider.submitTx({
context: {
handleResolutions: [mockHandleResolution]
},
signedTransaction: emptyUintArrayAsHexString
})
).rejects.toThrowError(/not_implemented/i);
});

it('does not throw an error if handles resolve to same addresses as in context', async () => {
mockServer = createMockOgmiosServer({ submitTx: { response: { success: true } } });
await listenPromise(mockServer, connection.port);
Expand Down