diff --git a/src/__tests__/unit/evaluation-options.test.ts b/src/__tests__/unit/evaluation-options.test.ts index 38877c16..fa9850cc 100644 --- a/src/__tests__/unit/evaluation-options.test.ts +++ b/src/__tests__/unit/evaluation-options.test.ts @@ -26,6 +26,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'throw', @@ -65,6 +66,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'throw', @@ -99,6 +101,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'allow', @@ -130,6 +133,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'allow', @@ -161,6 +165,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'throw', @@ -192,6 +197,7 @@ describe('Evaluation options evaluator', () => { stackTrace: { saveState: false }, + strictSortKey: false, throwOnInternalWriteError: true, transactionsPagesPerBatch: null, unsafeClient: 'skip', diff --git a/src/contract/EvaluationOptionsEvaluator.ts b/src/contract/EvaluationOptionsEvaluator.ts index 47d69184..4118fb11 100644 --- a/src/contract/EvaluationOptionsEvaluator.ts +++ b/src/contract/EvaluationOptionsEvaluator.ts @@ -108,14 +108,16 @@ export class EvaluationOptionsEvaluator { useKVStorage: (foreignOptions) => foreignOptions['useKVStorage'], useConstructor: (foreignOptions) => foreignOptions['useConstructor'], whitelistSources: () => this.rootOptions['whitelistSources'], - transactionsPagesPerBatch: () => this.rootOptions['transactionsPagesPerBatch'] + transactionsPagesPerBatch: () => this.rootOptions['transactionsPagesPerBatch'], + strictSortKey: () => this.rootOptions['strictSortKey'] }; private readonly notConflictingEvaluationOptions: (keyof EvaluationOptions)[] = [ 'useKVStorage', 'sourceType', 'useConstructor', - 'transactionsPagesPerBatch' + 'transactionsPagesPerBatch', + 'strictSortKey' ]; /** diff --git a/src/contract/HandlerBasedContract.ts b/src/contract/HandlerBasedContract.ts index 093f05a7..4de00042 100644 --- a/src/contract/HandlerBasedContract.ts +++ b/src/contract/HandlerBasedContract.ts @@ -647,6 +647,9 @@ export class HandlerBasedContract implements Contract { >; } cachedState = cachedState || (await stateEvaluator.latestAvailableState(contractTxId, upToSortKey)); + if (upToSortKey && this.evaluationOptions().strictSortKey && cachedState?.sortKey != upToSortKey) { + throw new Error(`State not cached at the exact required ${upToSortKey} sortKey`); + } this.logger.debug('cache lookup', benchmark.elapsed()); benchmark.reset(); diff --git a/src/core/modules/StateEvaluator.ts b/src/core/modules/StateEvaluator.ts index 98fe638d..47502bbe 100644 --- a/src/core/modules/StateEvaluator.ts +++ b/src/core/modules/StateEvaluator.ts @@ -154,6 +154,8 @@ export class DefaultEvaluationOptions implements EvaluationOptions { whitelistSources = []; transactionsPagesPerBatch = null; + + strictSortKey = false; } // an interface for the contract EvaluationOptions - can be used to change the behaviour of some features. @@ -243,9 +245,16 @@ export interface EvaluationOptions { // remote source for fetching most recent contract state, only applicable if remoteStateSyncEnabled is set to true remoteStateSyncSource: string; + // an array of source tx ids that are allowed to be evaluated by the SDK whitelistSources: string[]; + // how many interactions pages are evaluated in a single evaluation batch transactionsPagesPerBatch: number; + + // whether passing sortKey to some functions like viewState or readStateFor is strict + // - if it is, then we're requiring the SDK to have the state cached at this exact sortKey + // - so that SDK won't load and evaluated missing interactions + strictSortKey: boolean; } // https://github.com/nodejs/node/issues/40678 duh...