From 163918c997a005836392e74265305d8a7b623088 Mon Sep 17 00:00:00 2001 From: dtfiedler Date: Thu, 29 Feb 2024 13:00:46 -0700 Subject: [PATCH] feat(PE-5550): support sortKey for read interactions --- package.json | 2 +- src/api/warp.ts | 50 +++++++++++++++++++++++++++++++++--------- src/routes/contract.ts | 6 ++++- yarn.lock | 8 +++---- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index b23be48..a52ab90 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "koa2-swagger-ui": "^5.10.0", "lodash": "^4.17.21", "prom-client": "^14.2.0", - "warp-contracts": "^1.4.32", + "warp-contracts": "^1.4.36", "warp-contracts-lmdb": "^1.1.10", "warp-contracts-sqlite": "^1.0.2", "winston": "^3.8.2", diff --git a/src/api/warp.ts b/src/api/warp.ts index 9f4bef4..8a05b9a 100644 --- a/src/api/warp.ts +++ b/src/api/warp.ts @@ -25,6 +25,7 @@ import { import { DEFAULT_EVALUATION_OPTIONS, DEFAULT_PAGES_PER_BATCH, + DEFAULT_STATE_EVALUATION_TIMEOUT_MS, allowedContractTypes, } from '../constants'; import { ContractType, EvaluatedContractState } from '../types'; @@ -108,15 +109,18 @@ class ContractReadInteractionCacheKey { public readonly contractTxId: string, public readonly functionName: string, public readonly input: any, + public readonly sortKey?: string, public readonly warp: Warp, public readonly evaluationOptions: Partial, public readonly logger?: winston.Logger, ) {} toString(): string { - return `${this.contractTxId}-${this.functionName}-${createQueryParamHash( - this.input, - )}-${createQueryParamHash(this.evaluationOptions)}`; + return `${this.contractTxId}-${this.functionName}-${ + this.sortKey || 'latest' + }-${createQueryParamHash(this.input)}-${createQueryParamHash( + this.evaluationOptions, + )}`; } // Facilitate ReadThroughPromiseCache key derivation @@ -368,14 +372,23 @@ export async function readThroughToContractReadInteraction( cacheKey: ContractReadInteractionCacheKey, ): Promise<{ result: unknown; + sortKey: string | undefined; evaluationOptions: Partial; input: unknown; }> { - const { contractTxId, evaluationOptions, warp, logger, functionName, input } = - cacheKey; + const { + contractTxId, + evaluationOptions, + sortKey, + warp, + logger, + functionName, + input, + } = cacheKey; logger?.debug('Reading through to contract read interaction...', { contractTxId, cacheKey: cacheKey.toString(), + sortKey, }); const cacheId = cacheKey.toString(); @@ -386,11 +399,13 @@ export async function readThroughToContractReadInteraction( logger?.debug('Deduplicating in flight requests for read interaction...', { contractTxId, cacheKey: cacheKey.toString(), + sortKey, }); const { result } = await inFlightRequest; return { result, input, + sortKey, evaluationOptions, }; } @@ -406,11 +421,17 @@ export async function readThroughToContractReadInteraction( .setEvaluationOptions(evaluationOptions); // set cached value for multiple requests during initial promise - // TODO: add abort signal when view state supports it - const readInteractionPromise = contract.viewState({ - function: functionName, - ...input, - }); + const readInteractionPromise = contract.viewState( + { + function: functionName, + ...input, + }, + undefined, // tags + undefined, // transfer + undefined, // caller + AbortSignal.timeout(DEFAULT_STATE_EVALUATION_TIMEOUT_MS), + sortKey, + ); readRequestMap.set(cacheId, readInteractionPromise); readInteractionPromise @@ -418,6 +439,7 @@ export async function readThroughToContractReadInteraction( logger?.debug('Failed to evaluate read interaction on contract!', { contractTxId, cacheKey: cacheKey.toString(), + sortKey, error: error instanceof Error ? error.message : 'Unknown error', }); }) @@ -436,6 +458,7 @@ export async function readThroughToContractReadInteraction( if (!readInteractionResult) { logger?.error('Read interaction did not return a result!', { contractTxId, + sortKey, cacheKey: cacheKey.toString(), input, }); @@ -451,6 +474,7 @@ export async function readThroughToContractReadInteraction( contractTxId, cacheKey: cacheKey.toString(), input, + sortKey, error, errorMessage, }); @@ -459,12 +483,15 @@ export async function readThroughToContractReadInteraction( logger?.debug('Successfully evaluated read interaction on contract.', { contractTxId, + sortKey, + cacheKey: cacheKey.toString(), }); return { result, input, + sortKey, evaluationOptions, }; } @@ -475,12 +502,14 @@ export async function getContractReadInteraction({ logger, functionName, input, + sortKey, }: { contractTxId: string; warp: Warp; logger: winston.Logger; functionName: string; input: ParsedUrlQuery; + sortKey?: string | undefined; }): Promise<{ result: any; evaluationOptions: Partial; @@ -496,6 +525,7 @@ export async function getContractReadInteraction({ contractTxId, functionName, input, + sortKey, warp, evaluationOptions, logger, diff --git a/src/routes/contract.ts b/src/routes/contract.ts index f3c8edf..24c5921 100644 --- a/src/routes/contract.ts +++ b/src/routes/contract.ts @@ -541,7 +541,7 @@ export async function contractReservedHandler(ctx: KoaContext) { const queryParamsCastedToNumbers = ['qty', 'years', 'height']; export async function contractReadInteractionHandler(ctx: KoaContext) { - const { warp, logger: _logger } = ctx.state; + const { warp, logger: _logger, sortKey: requestedSortKey } = ctx.state; const { contractTxId, functionName } = ctx.params; const { query: input } = ctx.request; @@ -550,6 +550,8 @@ export async function contractReadInteractionHandler(ctx: KoaContext) { functionName, }); + // TODO: compute sortKey from blockHeight when provided + const parsedInput = Object.entries(input).reduce( (parsedParams: { [x: string]: any }, [key, value]) => { // parse known integer values for parameters we care about @@ -571,6 +573,7 @@ export async function contractReadInteractionHandler(ctx: KoaContext) { contractTxId, warp, logger, + sortKey: requestedSortKey, functionName, input: parsedInput, }); @@ -578,6 +581,7 @@ export async function contractReadInteractionHandler(ctx: KoaContext) { ctx.body = { contractTxId, result, + sortKey: requestedSortKey, evaluationOptions, }; } diff --git a/yarn.lock b/yarn.lock index 418f3f8..b1e90f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8223,10 +8223,10 @@ warp-contracts-sqlite@^1.0.2: better-sqlite3 "^8.3.0" safe-stable-stringify "^2.4.3" -warp-contracts@^1.4.32: - version "1.4.32" - resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.32.tgz#3d5c1ce973dde9d481618b1e060fac2de2870049" - integrity sha512-33OGr5xmarXFAfdmnJvAOrFLIT/Z6mp5BJEXw3dfaffM7mOGDsegWMDxNRoqWC2LFQFvvqnmuxq/FhEC6QRNgg== +warp-contracts@^1.4.36: + version "1.4.36" + resolved "https://registry.yarnpkg.com/warp-contracts/-/warp-contracts-1.4.36.tgz#dfdb69a34e314b2be5cb2ea8e51078a064c2fcff" + integrity sha512-2UeRxkry/wm0jme4d4CXvxUef+G3o3Al6Q2Tj2PQ5cvvK5GOfRfFiooaQIik88E6ZQNC9NJlvFUYBMVS9837CA== dependencies: archiver "^5.3.0" arweave "1.13.7"