feat: maxCallDepth implemented
This commit is contained in:
committed by
Piotr Pędziwiatr
parent
aeb8dc0be6
commit
d63ab29129
@@ -119,7 +119,7 @@ describe('Testing internal writes', () => {
|
||||
contractA = smartweave
|
||||
.contract(contractATxId)
|
||||
.setEvaluationOptions({
|
||||
internalWrites: true
|
||||
internalWrites: true,
|
||||
})
|
||||
.connect(wallet);
|
||||
contractB = smartweave
|
||||
@@ -271,6 +271,56 @@ describe('Testing internal writes', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with different maxDepths', () => {
|
||||
beforeEach(async () => {
|
||||
await deployContracts();
|
||||
});
|
||||
|
||||
it('should properly evaluate contractC state for maxDepth = 3', async () => {
|
||||
contractC.setEvaluationOptions({
|
||||
maxCallDepth: 3
|
||||
});
|
||||
|
||||
await contractB.writeInteraction({ function: 'add' });
|
||||
await contractB.writeInteraction({ function: 'add' });
|
||||
await contractC.writeInteraction({ function: 'add' });
|
||||
await mine();
|
||||
|
||||
await contractA.writeInteraction({
|
||||
function: 'writeInDepth',
|
||||
contractId1: contractBTxId,
|
||||
contractId2: contractCTxId,
|
||||
amount: 10
|
||||
});
|
||||
await mine();
|
||||
|
||||
expect((await contractC.readState()).state.counter).toEqual(231);
|
||||
expect((await contractC.readState()).state.counter).toEqual(231);
|
||||
});
|
||||
|
||||
it('should throw when evaluating ContractC state for maxDepth = 2', async () => {
|
||||
contractC.setEvaluationOptions({
|
||||
maxCallDepth: 2,
|
||||
ignoreExceptions: false
|
||||
});
|
||||
|
||||
await contractB.writeInteraction({ function: 'add' });
|
||||
await contractB.writeInteraction({ function: 'add' });
|
||||
await contractC.writeInteraction({ function: 'add' });
|
||||
await mine();
|
||||
|
||||
await contractA.writeInteraction({
|
||||
function: 'writeInDepth',
|
||||
contractId1: contractBTxId,
|
||||
contractId2: contractCTxId,
|
||||
amount: 10
|
||||
});
|
||||
await mine();
|
||||
|
||||
await expect(contractC.readState()).rejects.toThrow(/(.)*Error: Max call depth(.*)/);
|
||||
});
|
||||
});
|
||||
|
||||
async function mine() {
|
||||
await arweave.api.get('mine');
|
||||
}
|
||||
|
||||
@@ -115,4 +115,10 @@ export interface Contract<State = unknown> {
|
||||
getNetworkInfo(): NetworkInfoInterface;
|
||||
|
||||
getRootBlockHeight(): number | null;
|
||||
|
||||
parent(): Contract | null;
|
||||
|
||||
callDepth(): number;
|
||||
|
||||
evaluationOptions(): EvaluationOptions;
|
||||
}
|
||||
|
||||
@@ -37,19 +37,21 @@ import { NetworkInfoInterface } from 'arweave/node/network';
|
||||
export class HandlerBasedContract<State> implements Contract<State> {
|
||||
private readonly logger = LoggerFactory.INST.create('HandlerBasedContract');
|
||||
|
||||
private callStack: ContractCallStack;
|
||||
private evaluationOptions: EvaluationOptions = new DefaultEvaluationOptions();
|
||||
private _callStack: ContractCallStack;
|
||||
private _evaluationOptions: EvaluationOptions = new DefaultEvaluationOptions();
|
||||
|
||||
/**
|
||||
* current Arweave networkInfo that will be used for all operations of the SmartWeave protocol.
|
||||
* Only the 'root' contract call should read this data from Arweave - all the inner calls ("child" contracts)
|
||||
* should reuse this data from the parent ("calling") contract.
|
||||
*/
|
||||
private networkInfo?: NetworkInfoInterface = null;
|
||||
private _networkInfo?: NetworkInfoInterface = null;
|
||||
|
||||
private rootBlockHeight: number = null;
|
||||
private _rootBlockHeight: number = null;
|
||||
|
||||
private readonly innerWritesEvaluator = new InnerWritesEvaluator();
|
||||
private readonly _innerWritesEvaluator = new InnerWritesEvaluator();
|
||||
|
||||
private readonly _callDepth: number;
|
||||
|
||||
/**
|
||||
* wallet connected to this contract
|
||||
@@ -57,39 +59,56 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
protected wallet?: ArWallet;
|
||||
|
||||
constructor(
|
||||
readonly contractTxId: string,
|
||||
private readonly _contractTxId: string,
|
||||
protected readonly smartweave: SmartWeave,
|
||||
private readonly callingContract: Contract = null,
|
||||
private readonly callingInteraction: GQLNodeInterface = null
|
||||
private readonly _parentContract: Contract = null,
|
||||
private readonly _callingInteraction: GQLNodeInterface = null
|
||||
) {
|
||||
this.waitForConfirmation = this.waitForConfirmation.bind(this);
|
||||
if (callingContract != null) {
|
||||
this.networkInfo = callingContract.getNetworkInfo();
|
||||
this.rootBlockHeight = callingContract.getRootBlockHeight();
|
||||
if (_parentContract != null) {
|
||||
this._networkInfo = _parentContract.getNetworkInfo();
|
||||
this._rootBlockHeight = _parentContract.getRootBlockHeight();
|
||||
this._evaluationOptions = _parentContract.evaluationOptions();
|
||||
this._callDepth = _parentContract.callDepth() + 1;
|
||||
const interaction: InteractionCall = _parentContract.getCallStack().getInteraction(_callingInteraction.id);
|
||||
|
||||
console.log('Call depth', {
|
||||
callDepth: this._callDepth,
|
||||
max: this._evaluationOptions.maxCallDepth,
|
||||
options: this._evaluationOptions
|
||||
});
|
||||
|
||||
if (this._callDepth > this._evaluationOptions.maxCallDepth) {
|
||||
throw Error(
|
||||
`Max call depth of ${this._evaluationOptions.maxCallDepth} has been exceeded for interaction ${JSON.stringify(
|
||||
interaction.interactionInput
|
||||
)}`
|
||||
);
|
||||
}
|
||||
// sanity-check...
|
||||
if (this.networkInfo == null) {
|
||||
if (this._networkInfo == null) {
|
||||
throw Error('Calling contract should have the network info already set!');
|
||||
}
|
||||
this.logger.debug('Calling interaction id', callingInteraction.id);
|
||||
const interaction: InteractionCall = callingContract.getCallStack().getInteraction(callingInteraction.id);
|
||||
const callStack = new ContractCallStack(contractTxId);
|
||||
interaction.interactionInput.foreignContractCalls.set(contractTxId, callStack);
|
||||
this.callStack = callStack;
|
||||
this.logger.debug('Calling interaction id', _callingInteraction.id);
|
||||
const callStack = new ContractCallStack(_contractTxId, this._callDepth);
|
||||
interaction.interactionInput.foreignContractCalls.set(_contractTxId, callStack);
|
||||
this._callStack = callStack;
|
||||
} else {
|
||||
this.callStack = new ContractCallStack(contractTxId);
|
||||
this._callDepth = 0;
|
||||
this._callStack = new ContractCallStack(_contractTxId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async readState(blockHeight?: number, currentTx?: CurrentTx[]): Promise<EvalStateResult<State>> {
|
||||
this.logger.info('Read state for', {
|
||||
contractTxId: this.contractTxId,
|
||||
contractTxId: this._contractTxId,
|
||||
currentTx
|
||||
});
|
||||
this.maybeResetRootContract(blockHeight);
|
||||
|
||||
const { stateEvaluator } = this.smartweave;
|
||||
const benchmark = Benchmark.measure();
|
||||
const executionContext = await this.createExecutionContext(this.contractTxId, blockHeight);
|
||||
const executionContext = await this.createExecutionContext(this._contractTxId, blockHeight);
|
||||
this.logger.info('Execution Context', {
|
||||
blockHeight: executionContext.blockHeight,
|
||||
srcTxId: executionContext.contractDefinition?.srcTxId,
|
||||
@@ -109,7 +128,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
tags: Tags = [],
|
||||
transfer: ArTransfer = emptyTransfer
|
||||
): Promise<InteractionResult<State, View>> {
|
||||
this.logger.info('View state for', this.contractTxId);
|
||||
this.logger.info('View state for', this._contractTxId);
|
||||
return await this.callContract<Input, View>(input, blockHeight, tags, transfer);
|
||||
}
|
||||
|
||||
@@ -117,12 +136,12 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
input: Input,
|
||||
interactionTx: GQLNodeInterface
|
||||
): Promise<InteractionResult<State, View>> {
|
||||
this.logger.info(`View state for ${this.contractTxId}`, interactionTx);
|
||||
this.logger.info(`View state for ${this._contractTxId}`, interactionTx);
|
||||
return await this.callContractForTx<Input, View>(input, interactionTx);
|
||||
}
|
||||
|
||||
async dryWrite<Input>(input: Input, tags?: Tags, transfer?: ArTransfer): Promise<InteractionResult<State, unknown>> {
|
||||
this.logger.info('Dry-write for', this.contractTxId);
|
||||
this.logger.info('Dry-write for', this._contractTxId);
|
||||
return await this.callContract<Input>(input, undefined, tags, transfer);
|
||||
}
|
||||
|
||||
@@ -131,8 +150,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
transaction: GQLNodeInterface,
|
||||
currentTx?: CurrentTx[]
|
||||
): Promise<InteractionResult<State, unknown>> {
|
||||
this.logger.info(`Dry-write from transaction ${transaction.id} for ${this.contractTxId}`);
|
||||
return await this.callContractForTx<Input>(input, transaction, true, currentTx || []);
|
||||
this.logger.info(`Dry-write from transaction ${transaction.id} for ${this._contractTxId}`);
|
||||
return await this.callContractForTx<Input>(input, transaction, currentTx || []);
|
||||
}
|
||||
|
||||
async writeInteraction<Input>(
|
||||
@@ -146,10 +165,10 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
}
|
||||
const { arweave } = this.smartweave;
|
||||
|
||||
if (this.evaluationOptions.internalWrites) {
|
||||
if (this._evaluationOptions.internalWrites) {
|
||||
await this.callContract(input, undefined, tags, transfer);
|
||||
const callStack: ContractCallStack = this.getCallStack();
|
||||
const innerWrites = this.innerWritesEvaluator.eval(callStack);
|
||||
const innerWrites = this._innerWritesEvaluator.eval(callStack);
|
||||
this.logger.debug('Input', input);
|
||||
this.logger.debug('Callstack', callStack.print());
|
||||
|
||||
@@ -166,7 +185,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
const interactionTx = await createTx(
|
||||
this.smartweave.arweave,
|
||||
this.wallet,
|
||||
this.contractTxId,
|
||||
this._contractTxId,
|
||||
input,
|
||||
tags,
|
||||
transfer.target,
|
||||
@@ -180,7 +199,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.evaluationOptions.waitForConfirmation) {
|
||||
if (this._evaluationOptions.waitForConfirmation) {
|
||||
this.logger.info('Waiting for confirmation of', interactionTx.id);
|
||||
const benchmark = Benchmark.measure();
|
||||
await this.waitForConfirmation(interactionTx.id);
|
||||
@@ -190,15 +209,15 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
}
|
||||
|
||||
txId(): string {
|
||||
return this.contractTxId;
|
||||
return this._contractTxId;
|
||||
}
|
||||
|
||||
getCallStack(): ContractCallStack {
|
||||
return this.callStack;
|
||||
return this._callStack;
|
||||
}
|
||||
|
||||
getNetworkInfo(): NetworkInfoInterface {
|
||||
return this.networkInfo;
|
||||
return this._networkInfo;
|
||||
}
|
||||
|
||||
connect(wallet: ArWallet): Contract<State> {
|
||||
@@ -207,15 +226,15 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
}
|
||||
|
||||
setEvaluationOptions(options: Partial<EvaluationOptions>): Contract<State> {
|
||||
this.evaluationOptions = {
|
||||
...this.evaluationOptions,
|
||||
this._evaluationOptions = {
|
||||
...this._evaluationOptions,
|
||||
...options
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
getRootBlockHeight(): number {
|
||||
return this.rootBlockHeight;
|
||||
return this._rootBlockHeight;
|
||||
}
|
||||
|
||||
private async waitForConfirmation(transactionId: string): Promise<TransactionStatusResponse> {
|
||||
@@ -245,10 +264,10 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
|
||||
const benchmark = Benchmark.measure();
|
||||
// if this is a "root" call (ie. original call from SmartWeave's client)
|
||||
if (this.callingContract == null) {
|
||||
if (this._parentContract == null) {
|
||||
this.logger.debug('Reading network info for root call');
|
||||
currentNetworkInfo = await arweave.network.getInfo();
|
||||
this.networkInfo = currentNetworkInfo;
|
||||
this._networkInfo = currentNetworkInfo;
|
||||
} else {
|
||||
// if that's a call from within contract's source code
|
||||
this.logger.debug('Reusing network info from the calling contract');
|
||||
@@ -258,7 +277,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
// call to contract (from contract's source code) was loading network info independently
|
||||
// if the contract was evaluating for many minutes/hours, this could effectively lead to reading
|
||||
// state on different block heights...
|
||||
currentNetworkInfo = (this.callingContract as HandlerBasedContract<State>).networkInfo;
|
||||
currentNetworkInfo = (this._parentContract as HandlerBasedContract<State>)._networkInfo;
|
||||
}
|
||||
|
||||
if (blockHeight == null) {
|
||||
@@ -292,8 +311,8 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
interactionsLoader.load(
|
||||
contractTxId,
|
||||
cachedBlockHeight + 1,
|
||||
this.rootBlockHeight || this.networkInfo.height,
|
||||
this.evaluationOptions
|
||||
this._rootBlockHeight || this._networkInfo.height,
|
||||
this._evaluationOptions
|
||||
)
|
||||
]);
|
||||
this.logger.debug('contract and interactions load', benchmark.elapsed());
|
||||
@@ -315,7 +334,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
handler,
|
||||
smartweave: this.smartweave,
|
||||
contract: this,
|
||||
evaluationOptions: this.evaluationOptions,
|
||||
evaluationOptions: this._evaluationOptions,
|
||||
currentNetworkInfo,
|
||||
cachedState
|
||||
};
|
||||
@@ -345,7 +364,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
if (cachedBlockHeight != blockHeight) {
|
||||
[contractDefinition, interactions] = await Promise.all([
|
||||
definitionLoader.load<State>(contractTxId),
|
||||
await interactionsLoader.load(contractTxId, 0, blockHeight, this.evaluationOptions)
|
||||
await interactionsLoader.load(contractTxId, 0, blockHeight, this._evaluationOptions)
|
||||
]);
|
||||
sortedInteractions = await interactionsSorter.sort(interactions);
|
||||
} else {
|
||||
@@ -364,18 +383,18 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
handler,
|
||||
smartweave: this.smartweave,
|
||||
contract: this,
|
||||
evaluationOptions: this.evaluationOptions,
|
||||
evaluationOptions: this._evaluationOptions,
|
||||
caller,
|
||||
cachedState
|
||||
};
|
||||
}
|
||||
|
||||
private maybeResetRootContract(blockHeight?: number) {
|
||||
if (this.callingContract == null) {
|
||||
if (this._parentContract == null) {
|
||||
this.logger.debug('Clearing network info and call stack for the root contract');
|
||||
this.networkInfo = null;
|
||||
this.callStack = new ContractCallStack(this.txId());
|
||||
this.rootBlockHeight = blockHeight;
|
||||
this._networkInfo = null;
|
||||
this._callStack = new ContractCallStack(this.txId(), 0);
|
||||
this._rootBlockHeight = blockHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +411,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
}
|
||||
const { arweave, stateEvaluator } = this.smartweave;
|
||||
// create execution context
|
||||
let executionContext = await this.createExecutionContext(this.contractTxId, blockHeight, true);
|
||||
let executionContext = await this.createExecutionContext(this._contractTxId, blockHeight, true);
|
||||
|
||||
// add block data to execution context
|
||||
if (!executionContext.currentBlockData) {
|
||||
@@ -427,7 +446,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
const tx = await createTx(
|
||||
arweave,
|
||||
this.wallet,
|
||||
this.contractTxId,
|
||||
this._contractTxId,
|
||||
input,
|
||||
tags,
|
||||
transfer.target,
|
||||
@@ -458,22 +477,21 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
private async callContractForTx<Input, View = unknown>(
|
||||
input: Input,
|
||||
interactionTx: GQLNodeInterface,
|
||||
dryWrite = false,
|
||||
currentTx?: CurrentTx[]
|
||||
): Promise<InteractionResult<State, View>> {
|
||||
this.maybeResetRootContract();
|
||||
|
||||
const executionContext = await this.createExecutionContextFromTx(this.contractTxId, interactionTx);
|
||||
const executionContext = await this.createExecutionContextFromTx(this._contractTxId, interactionTx);
|
||||
const evalStateResult = await this.smartweave.stateEvaluator.eval<State>(executionContext, currentTx);
|
||||
|
||||
this.logger.debug('callContractForTx - evalStateResult', {
|
||||
result: evalStateResult.state,
|
||||
txId: this.contractTxId
|
||||
txId: this._contractTxId
|
||||
});
|
||||
|
||||
const interaction: ContractInteraction<Input> = {
|
||||
input,
|
||||
caller: this.callingContract.txId() //executionContext.caller
|
||||
caller: this._parentContract.txId() //executionContext.caller
|
||||
};
|
||||
|
||||
const interactionData: InteractionData<Input> = {
|
||||
@@ -482,16 +500,15 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
currentTx
|
||||
};
|
||||
|
||||
return await this.evalInteraction(interactionData, executionContext, evalStateResult, dryWrite);
|
||||
return await this.evalInteraction(interactionData, executionContext, evalStateResult);
|
||||
}
|
||||
|
||||
private async evalInteraction<Input, View = unknown>(
|
||||
interactionData: InteractionData<Input>,
|
||||
executionContext: ExecutionContext<State, HandlerApi<State>>,
|
||||
evalStateResult: EvalStateResult<State>,
|
||||
dryWrite = false
|
||||
evalStateResult: EvalStateResult<State>
|
||||
) {
|
||||
const interactionCall: InteractionCall = this.getCallStack().addInteractionData(interactionData, dryWrite);
|
||||
const interactionCall: InteractionCall = this.getCallStack().addInteractionData(interactionData);
|
||||
|
||||
const benchmark = Benchmark.measure();
|
||||
const result = await executionContext.handler.handle<Input, View>(
|
||||
@@ -503,7 +520,7 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
interactionCall.update({
|
||||
cacheHit: false,
|
||||
intermediaryCacheHit: false,
|
||||
outputState: this.evaluationOptions.stackTrace.saveState ? result.state : undefined,
|
||||
outputState: this._evaluationOptions.stackTrace.saveState ? result.state : undefined,
|
||||
executionTime: benchmark.elapsed(true) as number,
|
||||
valid: result.type === 'ok',
|
||||
errorMessage: result.errorMessage
|
||||
@@ -511,4 +528,16 @@ export class HandlerBasedContract<State> implements Contract<State> {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
parent(): Contract | null {
|
||||
return this._parentContract;
|
||||
}
|
||||
|
||||
callDepth(): number {
|
||||
return this._callDepth;
|
||||
}
|
||||
|
||||
evaluationOptions(): EvaluationOptions {
|
||||
return this._evaluationOptions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import { InteractionData, mapReplacer } from '@smartweave';
|
||||
export class ContractCallStack {
|
||||
readonly interactions: Map<string, InteractionCall> = new Map();
|
||||
|
||||
constructor(public readonly contractTxId: string, public readonly label: string = '') {}
|
||||
constructor(public readonly contractTxId: string, public readonly depth: number, public readonly label: string = '') {}
|
||||
|
||||
addInteractionData(interactionData: InteractionData<any>, dryWrite = false): InteractionCall {
|
||||
addInteractionData(interactionData: InteractionData<any>): InteractionCall {
|
||||
const { interaction, interactionTx } = interactionData;
|
||||
|
||||
const interactionCall = InteractionCall.create(
|
||||
|
||||
@@ -72,11 +72,14 @@ export class DefaultEvaluationOptions implements EvaluationOptions {
|
||||
|
||||
updateCacheForEachInteraction = true;
|
||||
|
||||
internalWrites = false;
|
||||
|
||||
maxCallDepth = 7; // your lucky number...
|
||||
|
||||
stackTrace = {
|
||||
saveState: false
|
||||
};
|
||||
|
||||
internalWrites: false;
|
||||
}
|
||||
|
||||
// an interface for the contract EvaluationOptions - can be used to change the behaviour of some of the features.
|
||||
@@ -96,13 +99,22 @@ export interface EvaluationOptions {
|
||||
// and caches it maybe more suitable to cache only after state has been fully evaluated)
|
||||
updateCacheForEachInteraction: boolean;
|
||||
|
||||
// a new, experimental enhancement of the protocol that allows for interactWrites from
|
||||
// smart contract's source code.
|
||||
internalWrites: boolean;
|
||||
|
||||
// maximum call depth between contracts
|
||||
// eg. ContractA calls ContractB,
|
||||
// then ContractB calls ContractC,
|
||||
// then ContractC calls ContractD
|
||||
// - call depth = 3
|
||||
// this is added as a protection from "stackoverflow" errors
|
||||
maxCallDepth: number;
|
||||
|
||||
// a set of options that control the behaviour of the stack trace generator
|
||||
stackTrace: {
|
||||
// whether output state should be saved for each interaction in the stack trace (may result in huuuuge json files!)
|
||||
saveState: boolean;
|
||||
};
|
||||
|
||||
// a new, experimental enhancement of the protocol that allows for interactWrites from
|
||||
// smart contract's source code.
|
||||
internalWrites: boolean;
|
||||
}
|
||||
|
||||
@@ -106,9 +106,11 @@ export class ContractHandlerApi<State> implements HandlerApi<State> {
|
||||
input
|
||||
});
|
||||
|
||||
const calleeContract = executionContext.smartweave
|
||||
.contract(contractTxId, executionContext.contract, this.swGlobal._activeTx)
|
||||
.setEvaluationOptions(executionContext.evaluationOptions);
|
||||
const calleeContract = executionContext.smartweave.contract(
|
||||
contractTxId,
|
||||
executionContext.contract,
|
||||
this.swGlobal._activeTx
|
||||
);
|
||||
|
||||
const result = await calleeContract.dryWriteFromTx<Input>(input, this.swGlobal._activeTx, [
|
||||
...(currentTx || []),
|
||||
@@ -139,9 +141,11 @@ export class ContractHandlerApi<State> implements HandlerApi<State> {
|
||||
to: contractTxId,
|
||||
input
|
||||
});
|
||||
const childContract = executionContext.smartweave
|
||||
.contract(contractTxId, executionContext.contract, this.swGlobal._activeTx)
|
||||
.setEvaluationOptions(executionContext.evaluationOptions);
|
||||
const childContract = executionContext.smartweave.contract(
|
||||
contractTxId,
|
||||
executionContext.contract,
|
||||
this.swGlobal._activeTx
|
||||
);
|
||||
|
||||
return await childContract.viewStateForTx(input, this.swGlobal._activeTx);
|
||||
};
|
||||
@@ -167,9 +171,11 @@ export class ContractHandlerApi<State> implements HandlerApi<State> {
|
||||
});
|
||||
|
||||
const { stateEvaluator } = executionContext.smartweave;
|
||||
const childContract = executionContext.smartweave
|
||||
.contract(contractTxId, executionContext.contract, interactionTx)
|
||||
.setEvaluationOptions(executionContext.evaluationOptions);
|
||||
const childContract = executionContext.smartweave.contract(
|
||||
contractTxId,
|
||||
executionContext.contract,
|
||||
interactionTx
|
||||
);
|
||||
|
||||
await stateEvaluator.onContractCall(interactionTx, executionContext, currentResult);
|
||||
|
||||
|
||||
@@ -91,9 +91,11 @@ export class DefaultStateEvaluator implements StateEvaluator {
|
||||
.getCallStack()
|
||||
.addInteractionData({ interaction: null, interactionTx, currentTx });
|
||||
|
||||
const writingContract = executionContext.smartweave
|
||||
.contract(writingContractTxId, executionContext.contract, interactionTx)
|
||||
.setEvaluationOptions(executionContext.evaluationOptions);
|
||||
const writingContract = executionContext.smartweave.contract(
|
||||
writingContractTxId,
|
||||
executionContext.contract,
|
||||
interactionTx
|
||||
);
|
||||
|
||||
this.logger.debug('Reading state of the calling contract', interactionTx.block.height);
|
||||
await writingContract.readState(interactionTx.block.height, [
|
||||
@@ -162,7 +164,7 @@ export class DefaultStateEvaluator implements StateEvaluator {
|
||||
this.logResult<State>(result, interactionTx, executionContext);
|
||||
|
||||
if (result.type === 'exception' && ignoreExceptions !== true) {
|
||||
throw new Error(`Exception while processing ${JSON.stringify(interaction)}:\n${result.result}`);
|
||||
throw new Error(`Exception while processing ${JSON.stringify(interaction)}:\n${result.errorMessage}`);
|
||||
}
|
||||
|
||||
validity[interactionTx.id] = result.type === 'ok';
|
||||
|
||||
Reference in New Issue
Block a user