Skip to content

Commit

Permalink
feat: throw error if trying to write to kv storage in a view function
Browse files Browse the repository at this point in the history
  • Loading branch information
ppedziwiatr committed Nov 9, 2023
1 parent 8c2d62e commit 28123c9
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
12 changes: 6 additions & 6 deletions src/core/modules/impl/handler/JsHandlerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,16 @@ export class JsHandlerApi<State> extends AbstractContractHandler<State> {

try {
await this.swGlobal.kv.open();
if (interaction.interactionType === 'write') {
await this.swGlobal.kv.begin();
}
await this.swGlobal.kv.begin();

const handlerResult = await Promise.race([timeoutPromise, this.contractFunction(stateClone, interaction)]);

if (handlerResult && (handlerResult.state !== undefined || handlerResult.result !== undefined)) {
if (interaction.interactionType === 'write') {
await this.swGlobal.kv.commit();
} else {
// view state function should not change anything in the kv storage
await this.swGlobal.kv.rollback();
}

let interactionEvent: InteractionCompleteEvent = null;
Expand Down Expand Up @@ -181,9 +182,7 @@ export class JsHandlerApi<State> extends AbstractContractHandler<State> {
// Will be caught below as unexpected exception.
throw new Error(`Unexpected result from contract: ${JSON.stringify(handlerResult)}`);
} catch (err) {
if (interaction.interactionType === 'write') {
await this.swGlobal.kv.rollback();
}
await this.swGlobal.kv.rollback();
switch (err.name) {
case KnownErrors.ContractError:
return {
Expand Down Expand Up @@ -238,6 +237,7 @@ export class JsHandlerApi<State> extends AbstractContractHandler<State> {

private setupSwGlobal<Input>({ interaction, interactionTx }: InteractionData<Input>) {
this.swGlobal._activeTx = interactionTx;
this.swGlobal.interactionType = interaction.interactionType;
this.swGlobal.caller = interaction.caller; // either contract tx id (for internal writes) or transaction.owner
}

Expand Down
1 change: 1 addition & 0 deletions src/core/modules/impl/handler/WasmHandlerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class WasmHandlerApi<State> extends AbstractContractHandler<State> {

this.swGlobal._activeTx = interactionTx;
this.swGlobal.caller = interaction.caller; // either contract tx id (for internal writes) or transaction.owner
this.swGlobal.interactionType = interaction.interactionType;
this.swGlobal.gasLimit = executionContext.evaluationOptions.gasLimit;
this.swGlobal.gasUsed = 0;

Expand Down
20 changes: 20 additions & 0 deletions src/legacy/smartweave-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CacheKey, SortKeyCache } from '../cache/SortKeyCache';
import { SortKeyCacheRangeOptions } from '../cache/SortKeyCacheRangeOptions';
import { InteractionState } from '../contract/states/InteractionState';
import { safeGet } from '../utils/utils';
import { ContractError, InteractionType } from "../core/modules/impl/HandlerExecutorFactory";

/**
*
Expand Down Expand Up @@ -66,6 +67,8 @@ export class SmartWeaveGlobal {

kv: KV;

interactionType: InteractionType;

constructor(
arweave: Arweave,
contract: { id: string; owner: string },
Expand Down Expand Up @@ -218,6 +221,13 @@ export class SWTransaction {
}
return this.smartWeaveGlobal._activeTx.source === 'redstone-sequencer' ? 'L2' : 'L1';
}

get interactionType(): InteractionType {
if (!this.smartWeaveGlobal._activeTx) {
throw new Error('No current Tx');
}
return this.smartWeaveGlobal.interactionType;
}
}

// tslint:disable-next-line: max-classes-per-file
Expand Down Expand Up @@ -282,7 +292,13 @@ export class KV {
) {}

async put(key: string, value: any): Promise<void> {
if (this._transaction.interactionType === 'view') {
throw new ContractError('Forbidden write operation for "view" function: "KV.put"');
}

this.checkStorageAvailable();


await this._storage.put(new CacheKey(key, this._transaction.sortKey), value);
}

Expand All @@ -304,6 +320,10 @@ export class KV {
}

async del(key: string): Promise<void> {
if (this._transaction.interactionType === 'view') {
throw new ContractError('Forbidden write operation for "view" function: "KV.del"');
}

this.checkStorageAvailable();
const sortKey = this._transaction.sortKey;

Expand Down

0 comments on commit 28123c9

Please sign in to comment.