From d21d1213a687aee872b0216d16ce3d048bfcaa6a Mon Sep 17 00:00:00 2001 From: Tadeuchi Date: Thu, 20 Jul 2023 11:47:20 +0200 Subject: [PATCH] fix: CIS should return null if nothing found --- .../internal-nested-read.test.ts | 27 +++++++++++++---- .../states/ContractInteractionState.ts | 8 +++-- src/contract/states/InteractionState.ts | 2 +- .../modules/impl/CacheableStateEvaluator.ts | 5 ---- .../modules/impl/DefaultStateEvaluator.ts | 30 ++++++++----------- 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/__tests__/integration/internal-writes/internal-nested-read.test.ts b/src/__tests__/integration/internal-writes/internal-nested-read.test.ts index c9e1563d..5d3f1d93 100644 --- a/src/__tests__/integration/internal-writes/internal-nested-read.test.ts +++ b/src/__tests__/integration/internal-writes/internal-nested-read.test.ts @@ -130,17 +130,31 @@ describe('Testing deep internal reads', () => { }); it('root contract should have the latest balance', async () => { - await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 200 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 25 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 25 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 50 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 50 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 50 }); await mineBlock(warp); await node20Contract.writeInteraction({ function: 'readBalanceFrom', tokenAddress: leafId, contractTxId: 'asd' }); await mineBlock(warp); - await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 400 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 200 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); + await mineBlock(warp); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); + await mineBlock(warp); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); + await mineBlock(warp); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); await mineBlock(warp); - await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 400 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); await mineBlock(warp); await node22Contract.writeInteraction({ function: 'readBalanceFrom', tokenAddress: leafId, contractTxId: 'asd' }); await mineBlock(warp); - await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 250 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 50 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); + await leafContract.writeInteraction({ function: 'increase', target: 'asd', qty: 100 }); await mineBlock(warp); await node21Contract.writeInteraction({ function: 'readBalanceFrom', tokenAddress: leafId, contractTxId: 'asd' }); await mineBlock(warp); @@ -154,7 +168,10 @@ describe('Testing deep internal reads', () => { await mineBlock(warp); - const rootResult = await warp.pst(rootId).readState(); + const rootResult = await warp.pst(rootId) + .setEvaluationOptions({ + cacheEveryNInteractions: 1, + }).readState(); expect(rootResult.cachedValue.state.balances['asd']).toEqual(1100); const node20Result = await warp.pst(node20Id).readState(); diff --git a/src/contract/states/ContractInteractionState.ts b/src/contract/states/ContractInteractionState.ts index cc871c84..60bfd158 100644 --- a/src/contract/states/ContractInteractionState.ts +++ b/src/contract/states/ContractInteractionState.ts @@ -30,7 +30,9 @@ export class ContractInteractionState implements InteractionState { } keys = keys.sort((a, b) => a.localeCompare(b)); const resultSortKey = keys[keys.length - 1]; - return new SortKeyCacheResult>(resultSortKey, states.get(resultSortKey)); + if (states.get(resultSortKey)) { + return new SortKeyCacheResult>(resultSortKey, states.get(resultSortKey)); + } } return null; } @@ -87,9 +89,9 @@ export class ContractInteractionState implements InteractionState { this._kv.clear(); } - async rollback(interaction: GQLNodeInterface): Promise { + async rollback(interaction: GQLNodeInterface, forceStateStoreToCache: boolean): Promise { try { - await this.doStoreJson(this._initialJson, interaction); + await this.doStoreJson(this._initialJson, interaction, forceStateStoreToCache); await this.rollbackKVs(); } finally { this.reset(); diff --git a/src/contract/states/InteractionState.ts b/src/contract/states/InteractionState.ts index cbae210b..5bd00b08 100644 --- a/src/contract/states/InteractionState.ts +++ b/src/contract/states/InteractionState.ts @@ -38,7 +38,7 @@ export interface InteractionState { * - IFF the result.type != 'ok'. * This ensures atomicity of state changes withing any given interaction - also in case of internal contract calls. */ - rollback(interaction: GQLNodeInterface): Promise; + rollback(interaction: GQLNodeInterface, forceStateStoreToCache: boolean): Promise; has(contractTxId: string, sortKey: string): boolean; diff --git a/src/core/modules/impl/CacheableStateEvaluator.ts b/src/core/modules/impl/CacheableStateEvaluator.ts index 18f9edba..64f0aa3d 100644 --- a/src/core/modules/impl/CacheableStateEvaluator.ts +++ b/src/core/modules/impl/CacheableStateEvaluator.ts @@ -86,11 +86,6 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator { ); } -// { -// contractTxId: this.contractDefinition.txId, -// interactionTxId: this.swGlobal.transaction.id -// } - async onStateEvaluated( transaction: GQLNodeInterface, executionContext: ExecutionContext, diff --git a/src/core/modules/impl/DefaultStateEvaluator.ts b/src/core/modules/impl/DefaultStateEvaluator.ts index d480e034..1dfc20e6 100644 --- a/src/core/modules/impl/DefaultStateEvaluator.ts +++ b/src/core/modules/impl/DefaultStateEvaluator.ts @@ -14,7 +14,6 @@ import { TagsParser } from './TagsParser'; import { VrfPluginFunctions } from '../../WarpPlugin'; import { BasicSortKeyCache } from '../../../cache/BasicSortKeyCache'; import { KnownErrors } from './handler/JsHandlerApi'; -import { genesisSortKey } from "./LexicographicalInteractionsSorter"; type EvaluationProgressInput = { contractTxId: string; @@ -91,17 +90,12 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { break; } + const missingInteraction = missingInteractions[i]; + currentSortKey = missingInteraction.sortKey; contract .interactionState() - .setInitial( - contract.txId(), - new EvalStateResult(currentState, validity, errorMessages), - lastConfirmedTxState?.tx?.sortKey || executionContext.cachedState?.sortKey || genesisSortKey - ); - - const missingInteraction = missingInteractions[i]; + .setInitial(contract.txId(), new EvalStateResult(currentState, validity, errorMessages), currentSortKey); const singleInteractionBenchmark = Benchmark.measure(); - currentSortKey = missingInteraction.sortKey; if (missingInteraction.vrf) { if (!vrfPlugin) { @@ -311,27 +305,27 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { } } + const forceStateStoreToCache = + executionContext.evaluationOptions.cacheEveryNInteractions > 0 && + i % executionContext.evaluationOptions.cacheEveryNInteractions === 0; // if that's the end of the root contract's interaction - commit all the uncommitted states to cache. if (contract.isRoot()) { contract.clearChildren(); // update the uncommitted state of the root contract if (lastConfirmedTxState) { - contract.interactionState().update(contract.txId(), lastConfirmedTxState.state, lastConfirmedTxState.tx.sortKey); + contract + .interactionState() + .update(contract.txId(), lastConfirmedTxState.state, lastConfirmedTxState.tx.sortKey); if (validity[missingInteraction.id]) { - let forceStateStoreToCache = false; - if (executionContext.evaluationOptions.cacheEveryNInteractions > 0) { - forceStateStoreToCache = i % executionContext.evaluationOptions.cacheEveryNInteractions === 0; - } await contract.interactionState().commit(missingInteraction, forceStateStoreToCache); } else { - await contract.interactionState().rollback(missingInteraction); + await contract.interactionState().rollback(missingInteraction, forceStateStoreToCache); } } } else { // if that's an inner contract call - only update the state in the uncommitted states - contract - .interactionState() - .update(contract.txId(), new EvalStateResult(currentState, validity, errorMessages), currentSortKey); + const interactionState = new EvalStateResult(currentState, validity, errorMessages); + contract.interactionState().update(contract.txId(), interactionState, currentSortKey); } } const evalStateResult = new EvalStateResult(currentState, validity, errorMessages);