Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of an evaluator device #576

Closed
michaelfig opened this issue Feb 19, 2020 · 4 comments
Closed

Implementation of an evaluator device #576

michaelfig opened this issue Feb 19, 2020 · 4 comments

Comments

@michaelfig
Copy link
Member

Refs #516

For an initial step, I'd like to create a device that allows a vat to evaluate code in a metered context (i.e. install a particular meter every time that code executes) and allows the kernel to clear the meter after every turn (empty stack).

Note that the current meter implementation is not bulletproof, so this is more just protection from unintentional runaways.

This may end up being a better abstraction than @agoric/evaluate when it comes to evaluating untrusted code, especially since @agoric/evaluate needs platform support. I expect the naive portable code-transformation/all-primordial-wrapping implementation will be improved and/or replaced by platform hooks when available.

@michaelfig
Copy link
Member Author

@warner, @Chris-Hibbert, @FUDCo PTAL.

@michaelfig
Copy link
Member Author

michaelfig commented Feb 19, 2020

Proposed device interface:

// ... kernel magic (to be explained in a forthcoming PR).
// and then we create the metered evaluator device.
const evaluator = buildMeteredEvaluator(replaceGlobalMeter, babelCore);

// In the vat that has access to the meteredEvaluator:
import { makeMeter } from '@agoric/transform-metering';

// Helper function to apply a meter to srcScript (a JS Script target).
function meteredEvaluate(srcScript, options = {}) {
  // Create a new meter just for these sources.
  const { meter, refillFacet } = makeMeter(/* any meter parameters */);
  function refillMeterInNewTurn(m) {
    // If we have exhausted, don't refill: the source should always abort.
    if (m === meter && !m.isExhausted()) {
      // Refill the entire meter, since we haven't exhausted yet.
      // We're just mitigating obvious runaways in a single turn, not any detailed accounting.
      Object.values(refillFacet).forEach(r => r());
    }
  }
  // Evaluate the sources, installing the meter each time their code runs, and refilling meters
  // every new turn.
  try {
    const ret = D(evaluator).evaluate(srcScript, { ...options, meter, refillMeterInNewTurn });
    return [true, ret, meter.isExhausted()];
  } catch (e) {
    return [false, e, meter.isExhausted()];
  }
}

const [normalReturn, value, exhausted] = meteredEvaluate(someSrc);
if (exhausted) {
  console.log('meter exhausted', exhausted);
} else if (normalReturn) {
  console.log('return value', value);
} else {
  console.log('exception', value);
}

@Chris-Hibbert
Copy link
Contributor

That looks good to me.

@michaelfig michaelfig changed the title Implementation of a metered-evaluator device Implementation of an evaluator device Feb 19, 2020
@michaelfig
Copy link
Member Author

I thought so too, but it looks like I can't return arbitrary objects across device boundaries. Back to the drawing board.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants