From b61090c4e4e96dd5f233482c7843d491c84c7955 Mon Sep 17 00:00:00 2001 From: ppedziwiatr Date: Sun, 18 Jun 2023 21:15:19 +0200 Subject: [PATCH] feat: iw validation --- src/contract/InnerWritesEvaluator.ts | 9 ++++- .../modules/impl/DefaultStateEvaluator.ts | 37 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/contract/InnerWritesEvaluator.ts b/src/contract/InnerWritesEvaluator.ts index a09f9985..4d0ed6fc 100644 --- a/src/contract/InnerWritesEvaluator.ts +++ b/src/contract/InnerWritesEvaluator.ts @@ -11,14 +11,19 @@ export class InnerWritesEvaluator { return result; } - private evalForeignCalls(rootContractTxId: string, interaction: InteractionCall, result: Array) { + evalForeignCalls( + rootContractTxId: string, + interaction: InteractionCall, + result: Array, + onlyDryWrites = true + ) { Object.keys(interaction.interactionInput.foreignContractCalls).forEach((foreignContractCallKey) => { const foreignContractCall = interaction.interactionInput.foreignContractCalls[foreignContractCallKey]; if (foreignContractCall.innerCallType == 'write') { Object.keys(foreignContractCall.interactions).forEach((k) => { const foreignInteraction = foreignContractCall.interactions[k]; if ( - foreignInteraction.interactionInput.dryWrite && + ((onlyDryWrites && foreignInteraction.interactionInput.dryWrite) || !onlyDryWrites) && !result.includes(foreignContractCall.contractTxId) && rootContractTxId !== foreignContractCall.contractTxId /*"write-backs"*/ ) { diff --git a/src/core/modules/impl/DefaultStateEvaluator.ts b/src/core/modules/impl/DefaultStateEvaluator.ts index 4046afee..bef26920 100644 --- a/src/core/modules/impl/DefaultStateEvaluator.ts +++ b/src/core/modules/impl/DefaultStateEvaluator.ts @@ -13,6 +13,7 @@ import { ContractInteraction, HandlerApi, InteractionResult } from './HandlerExe import { TagsParser } from './TagsParser'; import { VrfPluginFunctions } from '../../WarpPlugin'; import { BasicSortKeyCache } from '../../../cache/BasicSortKeyCache'; +import { InnerWritesEvaluator } from '../../../contract/InnerWritesEvaluator'; type EvaluationProgressInput = { contractTxId: string; @@ -239,22 +240,42 @@ export abstract class DefaultStateEvaluator implements StateEvaluator { this.logger.debug(`${indent(depth)}Interaction evaluation`, singleInteractionBenchmark.elapsed()); + if (result.type === 'exception' && ignoreExceptions !== true) { + throw new Error(`Exception while processing ${JSON.stringify(interaction)}:\n${result.errorMessage}`); + } + + if (internalWrites && contract.isRoot() && result.type === 'ok') { + const innerWritesEvaluator = new InnerWritesEvaluator(); + const iwEvaluatorResult = []; + innerWritesEvaluator.evalForeignCalls(contract.txId(), interactionCall, iwEvaluatorResult, false); + const tagsInnerWrites = this.tagsParser.getInteractWritesContracts(missingInteraction); + if ( + iwEvaluatorResult.length == tagsInnerWrites.length && + tagsInnerWrites.every((elem) => iwEvaluatorResult.includes(elem)) + ) { + validity[missingInteraction.id] = result.type === 'ok'; + currentState = result.state; + } else { + validity[missingInteraction.id] = false; + errorMessage = `[SDK] Inner writes do not match - tags: ${tagsInnerWrites}, evaluated: ${iwEvaluatorResult}`; + // console.error(errorMessage); + // console.dir(interactionCall, { depth: null }); + errorMessages[missingInteraction.id] = errorMessage; + } + } else { + validity[missingInteraction.id] = result.type === 'ok'; + currentState = result.state; + } + interactionCall.update({ cacheHit: false, outputState: stackTrace.saveState ? currentState : undefined, executionTime: singleInteractionBenchmark.elapsed(true) as number, valid: validity[missingInteraction.id], - errorMessage: errorMessage, + errorMessage, gasUsed: result.gasUsed }); - if (result.type === 'exception' && ignoreExceptions !== true) { - throw new Error(`Exception while processing ${JSON.stringify(interaction)}:\n${result.errorMessage}`); - } - - validity[missingInteraction.id] = result.type === 'ok'; - currentState = result.state; - const toCache = new EvalStateResult(currentState, validity, errorMessages); if (canBeCached(missingInteraction)) { lastConfirmedTxState = {