feat: interactWrites from within the contracts #37

This commit is contained in:
ppedziwiatr
2021-10-25 10:03:38 +02:00
committed by Piotr Pędziwiatr
parent 4c256f58e6
commit f139cfdda4
39 changed files with 6186 additions and 3607 deletions

View File

@@ -8,7 +8,8 @@ import {
} from '@smartweave/core';
import Arweave from 'arweave';
import { GQLNodeInterface } from '@smartweave/legacy';
import { Benchmark, LoggerFactory } from '@smartweave/logging';
import { LoggerFactory } from '@smartweave/logging';
import { CurrentTx } from '@smartweave/contract';
/**
* An implementation of DefaultStateEvaluator that adds caching capabilities
@@ -26,7 +27,7 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
async eval<State>(
executionContext: ExecutionContext<State, HandlerApi<State>>,
currentTx: { interactionTxId: string; contractTxId: string }[]
currentTx: CurrentTx[]
): Promise<EvalStateResult<State>> {
const requestedBlockHeight = executionContext.blockHeight;
this.cLogger.debug(`Requested state block height: ${requestedBlockHeight}`);
@@ -66,11 +67,9 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
cached: sortedInteractionsUpToBlock.length - missingInteractions.length
});
// TODO: this probably should be removed, as it seems to protect from
// some specific contract's implementation flaws
// (i.e. inner calls between two contracts that lead to inf. call loop - circular dependency).
// Instead - some kind of stack trace should be generated and "stackoverflow"
// exception should be thrown during contract's execution.
// TODO: this is tricky part, needs proper description
// for now: it prevents from infinite loop calls between calls that are making
// internal interact writes.
for (const entry of currentTx || []) {
if (entry.contractTxId === executionContext.contractDefinition.txId) {
const index = missingInteractions.findIndex((tx) => tx.node.id === entry.interactionTxId);
@@ -80,7 +79,7 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
contractTxId: entry.contractTxId,
interactionTxId: entry.interactionTxId
});
missingInteractions.splice(index, 1);
missingInteractions.splice(index);
}
}
}
@@ -110,6 +109,9 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
executionContext: ExecutionContext<State>,
state: EvalStateResult<State>
): Promise<void> {
if (lastInteraction.dry) {
return;
}
this.cLogger.debug(
`onStateEvaluated: cache update for contract ${executionContext.contractDefinition.txId} [${lastInteraction.block.height}]`
);
@@ -121,15 +123,19 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
async onStateUpdate<State>(
currentInteraction: GQLNodeInterface,
executionContext: ExecutionContext<State, unknown>,
executionContext: ExecutionContext<State>,
state: EvalStateResult<State>
): Promise<void> {
if (currentInteraction.dry) {
return;
}
if (executionContext.evaluationOptions.updateCacheForEachInteraction) {
await this.cache.put(
new BlockHeightKey(executionContext.contractDefinition.txId, currentInteraction.block.height),
state
);
}
await super.onStateUpdate(currentInteraction, executionContext, state);
}
async latestAvailableState<State>(
@@ -140,4 +146,20 @@ export class CacheableStateEvaluator extends DefaultStateEvaluator {
EvalStateResult<State>
>;
}
async onInternalWriteStateUpdate<State>(
currentInteraction: GQLNodeInterface,
contractTxId: string,
state: EvalStateResult<State>
): Promise<void> {
if (currentInteraction.dry) {
return;
}
this.cLogger.debug('Internal write state update:', {
height: currentInteraction.block.height,
contractTxId,
state
});
await this.cache.put(new BlockHeightKey(contractTxId, +currentInteraction.block.height), state);
}
}