Skip to content

Commit

Permalink
fix: prevent IW if no 'interact-write' tag is present
Browse files Browse the repository at this point in the history
  • Loading branch information
Piotr Pędziwiatr authored and ppedziwiatr committed Mar 11, 2024
1 parent 9403af8 commit 9768dc6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 13 deletions.
6 changes: 6 additions & 0 deletions src/core/modules/impl/TagsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,10 @@ export class TagsParser {
return t.name == WARP_TAGS.REQUEST_VRF && t.value === 'true';
});
}

hasInteractWriteTag(interaction: GQLNodeInterface, contractTxId: string): boolean {
return interaction.tags.some((t) => {
return t.name == WARP_TAGS.INTERACT_WRITE && t.value === contractTxId;
});
}
}
50 changes: 37 additions & 13 deletions src/core/modules/impl/handler/AbstractContractHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import { SmartWeaveGlobal } from '../../../../legacy/smartweave-global';
import { LoggerFactory } from '../../../../logging/LoggerFactory';
import { deepCopy } from '../../../../utils/utils';
import { ContractError, HandlerApi, InteractionData, InteractionResult } from '../HandlerExecutorFactory';
import { TagsParser } from '../TagsParser';
import { Contract } from '../../../../contract/Contract';

export abstract class AbstractContractHandler<State> implements HandlerApi<State> {
protected logger = LoggerFactory.INST.create('ContractHandler');
private readonly tagsParser = new TagsParser();

protected constructor(
protected readonly swGlobal: SmartWeaveGlobal,
Expand Down Expand Up @@ -46,30 +49,39 @@ export abstract class AbstractContractHandler<State> implements HandlerApi<State
if (!executionContext.evaluationOptions.internalWrites) {
throw new Error("Internal writes feature switched off. Change EvaluationOptions.internalWrites flag to 'true'");
}

const effectiveThrowOnError =
throwOnError == undefined ? executionContext.evaluationOptions.throwOnInternalWriteError : throwOnError;

const debugData = {
from: this.contractDefinition.txId,
to: contractTxId,
input
};

const activeTx = this.swGlobal._activeTx;
if (
!activeTx.dry &&
!this.tagsParser.hasInteractWriteTag(activeTx, contractTxId) &&
!this.isWriteBack(executionContext.contract, contractTxId)
) {
throw new Error(
`No interact write tag for interaction ${activeTx.id}: ${JSON.stringify(debugData)} \n ${JSON.stringify(
activeTx
)}`
);
}

const effectiveThrowOnError =
throwOnError == undefined ? executionContext.evaluationOptions.throwOnInternalWriteError : throwOnError;
this.logger.debug('swGlobal.write call:', debugData);

// The contract that we want to call and modify its state
const calleeContract = executionContext.warp.contract(contractTxId, executionContext.contract, {
callingInteraction: this.swGlobal._activeTx,
callingInteraction: activeTx,
callType: 'write'
});
const result = await calleeContract.applyInput<Input>(input, this.swGlobal._activeTx, executionContext.signal);
const result = await calleeContract.applyInput<Input>(input, activeTx, executionContext.signal);

this.logger.debug('Cache result?:', !this.swGlobal._activeTx.dry);
this.logger.debug('Cache result?:', !activeTx.dry);
const shouldAutoThrow =
result.type !== 'ok' &&
effectiveThrowOnError &&
(!this.swGlobal._activeTx.dry || (this.swGlobal._activeTx.dry && this.swGlobal._activeTx.strict));
result.type !== 'ok' && effectiveThrowOnError && (!activeTx.dry || (activeTx.dry && activeTx.strict));

const effectiveErrorMessage = shouldAutoThrow
? `Internal write auto error for call [${JSON.stringify(debugData)}]: ${result.errorMessage}`
Expand All @@ -78,7 +90,7 @@ export abstract class AbstractContractHandler<State> implements HandlerApi<State
const resultErrorMessages = effectiveErrorMessage
? {
...result.originalErrorMessages,
[this.swGlobal._activeTx.id]: effectiveErrorMessage
[activeTx.id]: effectiveErrorMessage
}
: result.originalErrorMessages;
calleeContract.interactionState().update(
Expand All @@ -87,11 +99,11 @@ export abstract class AbstractContractHandler<State> implements HandlerApi<State
state: result.state as State,
validity: {
...result.originalValidity,
[this.swGlobal._activeTx.id]: result.type == 'ok'
[activeTx.id]: result.type == 'ok'
},
errorMessages: resultErrorMessages
},
this.swGlobal._activeTx.sortKey
activeTx.sortKey
);

if (shouldAutoThrow) {
Expand Down Expand Up @@ -180,4 +192,16 @@ export abstract class AbstractContractHandler<State> implements HandlerApi<State
.get(this.swGlobal.contract.id, this.swGlobal._activeTx.sortKey)?.state;
};
}

private isWriteBack(contract: Contract<State>, target: string): boolean {
let current = contract as Contract;
while (current.parent()) {
current = current.parent();
if (current.txId() === target) {
return true;
}
}

return false;
}
}

0 comments on commit 9768dc6

Please sign in to comment.