diff --git a/packages/ERTP/package.json b/packages/ERTP/package.json index 91e4aeb68e7..88d333ef6cc 100644 --- a/packages/ERTP/package.json +++ b/packages/ERTP/package.json @@ -45,6 +45,7 @@ "@agoric/store": "^0.8.3", "@agoric/swingset-vat": "^0.30.2", "@agoric/vat-data": "^0.4.3", + "@agoric/zone": "^0.1.0", "@endo/eventual-send": "^0.17.2", "@endo/far": "^0.2.18", "@endo/marshal": "^0.8.5", diff --git a/packages/ERTP/src/issuerKit.js b/packages/ERTP/src/issuerKit.js index a4e2589a35c..979106aac0d 100644 --- a/packages/ERTP/src/issuerKit.js +++ b/packages/ERTP/src/issuerKit.js @@ -3,6 +3,7 @@ import { assert } from '@agoric/assert'; import { assertPattern } from '@agoric/store'; import { makeScalarBigMapStore } from '@agoric/vat-data'; +import { makeDurableZone } from '@agoric/zone/durable.js'; import { AssetKind, assertAssetKind } from './amountMath.js'; import { coerceDisplayInfo } from './displayInfo.js'; @@ -10,6 +11,7 @@ import { preparePaymentLedger } from './paymentLedger.js'; import './types-ambient.js'; +/** @typedef {import('@agoric/zone').Zone} Zone */ /** @typedef {import('@agoric/vat-data').Baggage} Baggage */ /** @@ -24,7 +26,7 @@ import './types-ambient.js'; /** * @template {AssetKind} K * @param {IssuerRecord} issuerRecord - * @param {Baggage} issuerBaggage + * @param {Zone} issuerZone * @param {ShutdownWithFailure} [optShutdownWithFailure] If this issuer fails * in the middle of an atomic action (which btw should never happen), it * potentially leaves its ledger in a corrupted state. If this function was @@ -36,7 +38,7 @@ import './types-ambient.js'; */ const setupIssuerKit = ( { name, assetKind, displayInfo, elementShape }, - issuerBaggage, + issuerZone, optShutdownWithFailure = undefined, ) => { assert.typeof(name, 'string'); @@ -56,7 +58,7 @@ const setupIssuerKit = ( /** @type {PaymentLedger} */ // @ts-expect-error could be instantiated with different subtype of AssetKind const { issuer, mint, brand, mintRecoveryPurse } = preparePaymentLedger( - issuerBaggage, + issuerZone, name, assetKind, cleanDisplayInfo, @@ -94,7 +96,8 @@ export const prepareIssuerKit = ( optShutdownWithFailure = undefined, ) => { const issuerRecord = issuerBaggage.get(INSTANCE_KEY); - return setupIssuerKit(issuerRecord, issuerBaggage, optShutdownWithFailure); + const issuerZone = makeDurableZone(issuerBaggage); + return setupIssuerKit(issuerRecord, issuerZone, optShutdownWithFailure); }; harden(prepareIssuerKit); @@ -150,7 +153,8 @@ export const makeDurableIssuerKit = ( ) => { const issuerData = harden({ name, assetKind, displayInfo, elementShape }); issuerBaggage.init(INSTANCE_KEY, issuerData); - return setupIssuerKit(issuerData, issuerBaggage, optShutdownWithFailure); + const issuerZone = makeDurableZone(issuerBaggage); + return setupIssuerKit(issuerData, issuerZone, optShutdownWithFailure); }; harden(makeDurableIssuerKit); diff --git a/packages/ERTP/src/payment.js b/packages/ERTP/src/payment.js index 9c3a0e64428..3a7c82eaf0b 100644 --- a/packages/ERTP/src/payment.js +++ b/packages/ERTP/src/payment.js @@ -1,21 +1,19 @@ // @jessie-check import { initEmpty } from '@agoric/store'; -import { prepareExoClass } from '@agoric/vat-data'; -/** @typedef {import('@agoric/vat-data').Baggage} Baggage */ +/** @typedef {import('@agoric/zone').Zone} Zone */ /** * @template {AssetKind} K - * @param {Baggage} issuerBaggage + * @param {Zone} issuerZone * @param {string} name * @param {Brand} brand * @param {InterfaceGuard} PaymentI * @returns {() => Payment} */ -export const preparePaymentKind = (issuerBaggage, name, brand, PaymentI) => { - const makePayment = prepareExoClass( - issuerBaggage, +export const preparePaymentKind = (issuerZone, name, brand, PaymentI) => { + const makePayment = issuerZone.exoClass( `${name} payment`, PaymentI, initEmpty, diff --git a/packages/ERTP/src/paymentLedger.js b/packages/ERTP/src/paymentLedger.js index 330300b5e0f..a2c9717fa5d 100644 --- a/packages/ERTP/src/paymentLedger.js +++ b/packages/ERTP/src/paymentLedger.js @@ -3,11 +3,7 @@ /* eslint-disable no-use-before-define */ import { isPromise } from '@endo/promise-kit'; import { mustMatch, M, keyEQ } from '@agoric/store'; -import { - provideDurableWeakMapStore, - prepareExo, - provide, -} from '@agoric/vat-data'; +import { provide } from '@agoric/vat-data'; import { AmountMath } from './amountMath.js'; import { preparePaymentKind } from './payment.js'; import { preparePurseKind } from './purse.js'; @@ -15,7 +11,7 @@ import { preparePurseKind } from './purse.js'; import '@agoric/store/exported.js'; import { BrandI, makeIssuerInterfaces } from './typeGuards.js'; -/** @typedef {import('@agoric/vat-data').Baggage} Baggage */ +/** @typedef {import('@agoric/zone').Zone} Zone */ const { details: X, quote: q, Fail } = assert; @@ -74,7 +70,7 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => { * payments. All minting and transfer authority originates here. * * @template {AssetKind} K - * @param {Baggage} issuerBaggage + * @param {import('@agoric/zone').Zone} issuerZone * @param {string} name * @param {K} assetKind * @param {DisplayInfo} displayInfo @@ -83,7 +79,7 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => { * @returns {PaymentLedger} */ export const preparePaymentLedger = ( - issuerBaggage, + issuerZone, name, assetKind, displayInfo, @@ -91,8 +87,12 @@ export const preparePaymentLedger = ( optShutdownWithFailure = undefined, ) => { /** @type {Brand} */ - // @ts-expect-error XXX callWhen - const brand = prepareExo(issuerBaggage, `${name} brand`, BrandI, { + // Should be + // at-ts-expect-error XXX callWhen + // but ran into the usual disagreement between local lint and CI + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error + // @ts-ignore + const brand = issuerZone.exo(`${name} brand`, BrandI, { isMyIssuer(allegedIssuer) { // BrandI delays calling this method until `allegedIssuer` is a Remotable return allegedIssuer === issuer; @@ -121,7 +121,7 @@ export const preparePaymentLedger = ( amountShape, ); - const makePayment = preparePaymentKind(issuerBaggage, name, brand, PaymentI); + const makePayment = preparePaymentKind(issuerZone, name, brand, PaymentI); /** @type {ShutdownWithFailure} */ const shutdownLedgerWithFailure = reason => { @@ -139,11 +139,9 @@ export const preparePaymentLedger = ( }; /** @type {WeakMapStore} */ - const paymentLedger = provideDurableWeakMapStore( - issuerBaggage, - 'paymentLedger', - { valueShape: amountShape }, - ); + const paymentLedger = issuerZone.weakMapStore('paymentLedger', { + valueShape: amountShape, + }); /** * A withdrawn live payment is associated with the recovery set of @@ -165,10 +163,7 @@ export const preparePaymentLedger = ( * * @type {WeakMapStore>} */ - const paymentRecoverySets = provideDurableWeakMapStore( - issuerBaggage, - 'paymentRecoverySets', - ); + const paymentRecoverySets = issuerZone.weakMapStore('paymentRecoverySets'); /** * To maintain the invariants listed in the `paymentRecoverySets` comment, @@ -315,7 +310,7 @@ export const preparePaymentLedger = ( }; const makeEmptyPurse = preparePurseKind( - issuerBaggage, + issuerZone, name, assetKind, brand, @@ -327,8 +322,12 @@ export const preparePaymentLedger = ( ); /** @type {Issuer} */ - // @ts-expect-error cast due to callWhen discrepancy - const issuer = prepareExo(issuerBaggage, `${name} issuer`, IssuerI, { + // Should be + // at-ts-expect-error cast due to callWhen discrepancy + // but ran into the usual disagreement between local lint and CI + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error + // @ts-ignore + const issuer = issuerZone.exo(`${name} issuer`, IssuerI, { getBrand() { return brand; }, @@ -375,26 +374,41 @@ export const preparePaymentLedger = ( }, }); + /** + * @template {any} V + * @param {Zone} zone + * @param {string} key + * @param {(k: string) => V} makeValue + * @returns {V} + */ + const provideFromZone = (zone, key, makeValue) => { + const map = zone.mapStore(`singleton_${key}_store`); + return provide(map, key, makeValue); + }; + harden(provideFromZone); + /** * Provides for the recovery of newly minted but not-yet-deposited payments. * * Because the `mintRecoveryPurse` is placed in baggage, even if the * caller of `makeIssuerKit` drops it on the floor, it can still be * recovered in an emergency upgrade. - * - * @type {Purse} */ - const mintRecoveryPurse = provide(issuerBaggage, 'mintRecoveryPurse', () => - makeEmptyPurse(), + const mintRecoveryPurse = /** @type {Purse} */ ( + provideFromZone(issuerZone, 'mintRecoveryPurse', () => makeEmptyPurse()) ); /** @type {Mint} */ - const mint = prepareExo(issuerBaggage, `${name} mint`, MintI, { + const mint = issuerZone.exo(`${name} mint`, MintI, { getIssuer() { return issuer; }, mintPayment(newAmount) { - // @ts-expect-error checked cast + // Should be + // at-ts-expect-error checked cast + // but ran into the usual disagreement between local lint and CI + // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error + // @ts-ignore newAmount = coerce(newAmount); mustMatch(newAmount, amountShape, 'minted amount'); // `rawPayment` is not associated with any recovery set, and diff --git a/packages/ERTP/src/purse.js b/packages/ERTP/src/purse.js index 35d766eda79..c8e413cbf7c 100644 --- a/packages/ERTP/src/purse.js +++ b/packages/ERTP/src/purse.js @@ -1,12 +1,22 @@ import { M } from '@agoric/store'; -import { prepareExoClassKit, makeScalarBigSetStore } from '@agoric/vat-data'; import { AmountMath } from './amountMath.js'; import { makeTransientNotifierKit } from './transientNotifier.js'; +/** @typedef {import('@endo/eventual-send').Callable} Callable */ +/** @typedef {import('@agoric/zone').Zone} Zone */ + const { Fail } = assert; +/** + * @param {Zone} issuerZone + * @param {string} name + * @param {AssetKind} assetKind + * @param {Brand} brand + * @param {Record} PurseIKit + * @param {Record} purseMethods + */ export const preparePurseKind = ( - issuerBaggage, + issuerZone, name, assetKind, brand, @@ -17,6 +27,7 @@ export const preparePurseKind = ( // Note: Virtual for high cardinality, but *not* durable, and so // broken across an upgrade. + // TODO propagate zonifying to notifiers, maybe? const { provideNotifier, update: updateBalance } = makeTransientNotifierKit(); const updatePurseBalance = (state, newPurseBalance, purse) => { @@ -31,17 +42,14 @@ export const preparePurseKind = ( // that created depositFacet as needed. But this approach ensures a constant // identity for the facet and exercises the multi-faceted object style. const { depositInternal, withdrawInternal } = purseMethods; - const makePurseKit = prepareExoClassKit( - issuerBaggage, + const makePurseKit = issuerZone.exoClassKit( `${name} Purse`, PurseIKit, () => { const currentBalance = AmountMath.makeEmpty(brand, assetKind); /** @type {SetStore} */ - const recoverySet = makeScalarBigSetStore('recovery set', { - durable: true, - }); + const recoverySet = issuerZone.detached().setStore('recovery set'); return { currentBalance, diff --git a/packages/ERTP/src/transientNotifier.js b/packages/ERTP/src/transientNotifier.js index 190ec705ce0..d708567fc32 100644 --- a/packages/ERTP/src/transientNotifier.js +++ b/packages/ERTP/src/transientNotifier.js @@ -4,6 +4,8 @@ import { makeScalarBigWeakMapStore } from '@agoric/vat-data'; import { provideLazy } from '@agoric/store'; import { makeNotifierKit } from '@agoric/notifier'; +// TODO propagate zonifying to notifiers, maybe? + // Note: Virtual for high cardinality, but *not* durable, and so // broken across an upgrade. export const makeTransientNotifierKit = () => {