warp-contracts / warp

An implementation of the Arweave SmartWeave smart contracts protocol.
MIT License
159 stars 44 forks source link

[FEATURE] - support for AbortController when reading contract state #415

Closed dtfiedler closed 1 year ago

dtfiedler commented 1 year ago

Is your feature request related to a problem? Please describe. Sometimes contract states can be huge, and dApps running in the browser (or lean services) may want to abort evaluating contract state if it's evaluation time is too long or consuming too much memory.

Describe the solution you'd like It would be nice to be able to provide a node AbortController signal when evaluating contract state to cancel in inflight request, similar to the node:fetch API.

Example:

try {
  const abortController = new AbortController(); 
  const timeout = setTimeout(() => abortController.abort(), 3000); // give warp 3 seconds to evaluate state, if it can't by then, abort
  const { cachedValue } = await contract.readState(id, { signal: abortController.signal });
  clearTimeout(timeout);
  console.log('Successfully read contract state!);
} catch (error: unknown) {
  if (error.name === 'AbortError') {
    console.error('State took too long to evaluate!);
  }
 // handle other load errors
}

Describe alternatives you've considered You can achieve this by wrapping readState in a setTimeout() call, or using Promise.race with a setTimeout but it would be nice if readState() natively supported abort controllers to follow existing async AbortController patterns.

e.g.

const stateEvaluationTimeout = async (id: string ): Promise<PSTState | unknown> => {
    return Promise.race([contract.readState(id), new Promise((_, reject) => setTimeout(() => reject('Evaluation timed out.'), EVALUATION_TIMEOUT))])
};
try {
  const { cachedValue } = await stateEvaluationTimeout(id);
  // do something with the state
} catch(error){
   console.error(error);
   // do something with the error
}

Additional context Some details on AbortController

ppedziwiatr commented 1 year ago

Hmm, we already have evaluation time limit for each interaction (https://github.com/warp-contracts/warp/blob/main/src/core/modules/StateEvaluator.ts#L122), not sure if we want to add a 'global' limit, since it's more of an 'external' client feature (the one, that is using warp) and we're trying to avoid 'feature creep' in the SDK...

Also - not sure if AbortController is the best solution here...IMO a better one could be creating a separate Worker that evaluates the contract code - and calling worker.teminate after some specific timeout...but again - it's kinda 'external' feature to the SDK itself...anyway, we will discuss this internally..