UNPKG

@metamask/ocap-kernel

Version:
202 lines 11.7 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _VatSyscall_instances, _VatSyscall_kernelQueue, _VatSyscall_kernelStore, _VatSyscall_logger, _VatSyscall_handleSyscallSend, _VatSyscall_handleSyscallResolve, _VatSyscall_handleSyscallSubscribe, _VatSyscall_handleSyscallDropImports, _VatSyscall_handleSyscallRetireImports, _VatSyscall_handleSyscallExportCleanup, _VatSyscall_recordVatFatalSyscall; import { Logger } from "@metamask/logger"; import { makeError } from "./services/kernel-marshal.mjs"; import { parseRef } from "./store/utils/parse-ref.mjs"; import { coerceMessage } from "./types.mjs"; /** * A VatSyscall is a class that handles syscalls from a vat. * * This class is responsible for handling syscalls from a vat, including * sending messages, resolving promises, and dropping imports. */ export class VatSyscall { /** * Construct a new VatSyscall instance. * * @param props - The properties for the VatSyscall. * @param props.vatId - The ID of the vat. * @param props.kernelQueue - The kernel's run queue. * @param props.kernelStore - The kernel's store. * @param props.logger - The logger for the VatSyscall. */ constructor({ vatId, kernelQueue, kernelStore, logger }) { _VatSyscall_instances.add(this); /** The kernel's run queue */ _VatSyscall_kernelQueue.set(this, void 0); /** The kernel's store */ _VatSyscall_kernelStore.set(this, void 0); /** Logger for outputting messages (such as errors) to the console */ _VatSyscall_logger.set(this, void 0); this.vatId = vatId; __classPrivateFieldSet(this, _VatSyscall_kernelQueue, kernelQueue, "f"); __classPrivateFieldSet(this, _VatSyscall_kernelStore, kernelStore, "f"); __classPrivateFieldSet(this, _VatSyscall_logger, logger ?? new Logger({ tags: [`[vat ${vatId}]`, 'syscall'] }), "f"); } /** * Handle a syscall from the vat. * * @param vso - The syscall that was received. * @returns The result of the syscall. */ handleSyscall(vso) { try { this.illegalSyscall = undefined; this.vatRequestedTermination = undefined; // This is a safety check - this case should never happen if (!__classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").isVatActive(this.vatId)) { __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_recordVatFatalSyscall).call(this, 'vat not found'); return harden(['error', 'vat not found']); } const kso = __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").translateSyscallVtoK(this.vatId, vso); const [op] = kso; const { vatId } = this; const { log } = console; switch (op) { case 'send': { // [KRef, Message]; const [, target, message] = kso; log(`@@@@ ${vatId} syscall send ${target}<-${JSON.stringify(message)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallSend).call(this, target, coerceMessage(message)); break; } case 'subscribe': { // [KRef]; const [, promise] = kso; log(`@@@@ ${vatId} syscall subscribe ${promise}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallSubscribe).call(this, promise); break; } case 'resolve': { // [VatOneResolution[]]; const [, resolutions] = kso; log(`@@@@ ${vatId} syscall resolve ${JSON.stringify(resolutions)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallResolve).call(this, resolutions); break; } case 'exit': { // [boolean, SwingSetCapData]; const [, isFailure, info] = kso; log(`@@@@ ${vatId} syscall exit fail=${isFailure} ${JSON.stringify(info)}`); this.vatRequestedTermination = { reject: isFailure, info }; break; } case 'dropImports': { // [KRef[]]; const [, refs] = kso; log(`@@@@ ${vatId} syscall dropImports ${JSON.stringify(refs)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallDropImports).call(this, refs); break; } case 'retireImports': { // [KRef[]]; const [, refs] = kso; log(`@@@@ ${vatId} syscall retireImports ${JSON.stringify(refs)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallRetireImports).call(this, refs); break; } case 'retireExports': { // [KRef[]]; const [, refs] = kso; log(`@@@@ ${vatId} syscall retireExports ${JSON.stringify(refs)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallExportCleanup).call(this, refs, true); break; } case 'abandonExports': { // [KRef[]]; const [, refs] = kso; log(`@@@@ ${vatId} syscall abandonExports ${JSON.stringify(refs)}`); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_handleSyscallExportCleanup).call(this, refs, false); break; } case 'callNow': case 'vatstoreGet': case 'vatstoreGetNextKey': case 'vatstoreSet': case 'vatstoreDelete': { console.warn(`vat ${vatId} issued invalid syscall ${op} `, vso); break; } default: // Compile-time exhaustiveness check // eslint-disable-next-line @typescript-eslint/restrict-template-expressions console.warn(`vat ${vatId} issued unknown syscall ${op} `, vso); break; } return harden(['ok', null]); } catch (error) { __classPrivateFieldGet(this, _VatSyscall_logger, "f").error(`Fatal syscall error in vat ${this.vatId}`, error); __classPrivateFieldGet(this, _VatSyscall_instances, "m", _VatSyscall_recordVatFatalSyscall).call(this, 'syscall translation error: prepare to die'); return harden([ 'error', error instanceof Error ? error.message : String(error), ]); } } } _VatSyscall_kernelQueue = new WeakMap(), _VatSyscall_kernelStore = new WeakMap(), _VatSyscall_logger = new WeakMap(), _VatSyscall_instances = new WeakSet(), _VatSyscall_handleSyscallSend = function _VatSyscall_handleSyscallSend(target, message) { __classPrivateFieldGet(this, _VatSyscall_kernelQueue, "f").enqueueSend(target, message); }, _VatSyscall_handleSyscallResolve = function _VatSyscall_handleSyscallResolve(resolutions) { __classPrivateFieldGet(this, _VatSyscall_kernelQueue, "f").resolvePromises(this.vatId, resolutions); }, _VatSyscall_handleSyscallSubscribe = function _VatSyscall_handleSyscallSubscribe(kpid) { const kp = __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").getKernelPromise(kpid); if (kp.state === 'unresolved') { __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").addPromiseSubscriber(this.vatId, kpid); } else { __classPrivateFieldGet(this, _VatSyscall_kernelQueue, "f").enqueueNotify(this.vatId, kpid); } }, _VatSyscall_handleSyscallDropImports = function _VatSyscall_handleSyscallDropImports(krefs) { for (const kref of krefs) { const { direction, isPromise } = parseRef(kref); // We validate it's an import - meaning this vat received this object from somewhere else if (direction === 'export' || isPromise) { throw Error(`vat ${this.vatId} issued invalid syscall dropImports for ${kref}`); } __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").clearReachableFlag(this.vatId, kref); } }, _VatSyscall_handleSyscallRetireImports = function _VatSyscall_handleSyscallRetireImports(krefs) { for (const kref of krefs) { const { direction, isPromise } = parseRef(kref); // We validate it's an import - meaning this vat received this object from somewhere else if (direction === 'export' || isPromise) { throw Error(`vat ${this.vatId} issued invalid syscall retireImports for ${kref}`); } if (__classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").getReachableFlag(this.vatId, kref)) { throw Error(`syscall.retireImports but ${kref} is still reachable`); } // deleting the clist entry will decrement the recognizable count, but // not the reachable count (because it was unreachable, as we asserted) __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").forgetKref(this.vatId, kref); } }, _VatSyscall_handleSyscallExportCleanup = function _VatSyscall_handleSyscallExportCleanup(krefs, checkReachable) { const action = checkReachable ? 'retire' : 'abandon'; for (const kref of krefs) { const { direction, isPromise } = parseRef(kref); // We validate it's an export - meaning this vat created/owns this object if (direction === 'import' || isPromise) { throw Error(`vat ${this.vatId} issued invalid syscall ${action}Exports for ${kref}`); } if (checkReachable) { if (__classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").getReachableFlag(this.vatId, kref)) { throw Error(`syscall.${action}Exports but ${kref} is still reachable`); } } __classPrivateFieldGet(this, _VatSyscall_kernelStore, "f").forgetKref(this.vatId, kref); __classPrivateFieldGet(this, _VatSyscall_logger, "f").debug(`${action}Exports: deleted object ${kref}`); } }, _VatSyscall_recordVatFatalSyscall = function _VatSyscall_recordVatFatalSyscall(error) { this.illegalSyscall = { vatId: this.vatId, info: makeError(error) }; }; //# sourceMappingURL=VatSyscall.mjs.map