Skip to content

Commit

Permalink
refactor(ertp): ertp on zones (#7116)
Browse files Browse the repository at this point in the history
* refactor(ertp): ertp on zones

* fixup! better and worse typing

* fixup! format
  • Loading branch information
erights authored Feb 24, 2024
1 parent f05590f commit be6d970
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 82 deletions.
1 change: 1 addition & 0 deletions packages/ERTP/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@agoric/notifier": "^0.6.2",
"@agoric/store": "^0.9.2",
"@agoric/vat-data": "^0.5.2",
"@agoric/zone": "^0.2.2",
"@endo/eventual-send": "^1.1.2",
"@endo/far": "^1.0.4",
"@endo/marshal": "^1.3.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/ERTP/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@
export * from './amountMath.js';
export * from './issuerKit.js';
export * from './typeGuards.js';

/**
* Importing Baggage from `@agoric/ertp` is deprecated. Import Baggage from
* `@agoric/vat-data` instead
*
* @typedef {import('@agoric/vat-data').Baggage} Baggage
*/
25 changes: 12 additions & 13 deletions packages/ERTP/src/issuerKit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
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';
import { preparePaymentLedger } from './paymentLedger.js';

import './types-ambient.js';

// TODO Why does TypeScript lose the `MapStore` typing of `Baggage` here, even
// though it knows the correct type at the exporting `@agoric/vat-data`
/** @typedef {import('@agoric/vat-data').Baggage} Baggage */

/**
* @template {AssetKind} K
* @typedef {object} IssuerRecord
Expand All @@ -28,7 +25,7 @@ import './types-ambient.js';
*
* @template {AssetKind} K
* @param {IssuerRecord<K>} issuerRecord
* @param {Baggage} issuerBaggage
* @param {import('@agoric/zone').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
Expand All @@ -40,7 +37,7 @@ import './types-ambient.js';
*/
const setupIssuerKit = (
{ name, assetKind, displayInfo, elementShape },
issuerBaggage,
issuerZone,
optShutdownWithFailure = undefined,
) => {
assert.typeof(name, 'string');
Expand All @@ -60,7 +57,7 @@ const setupIssuerKit = (
/** @type {PaymentLedger<K>} */
// @ts-expect-error could be instantiated with different subtype of AssetKind
const { issuer, mint, brand, mintRecoveryPurse } = preparePaymentLedger(
issuerBaggage,
issuerZone,
name,
assetKind,
cleanDisplayInfo,
Expand All @@ -86,7 +83,7 @@ const INSTANCE_KEY = 'issuer';
* make a new one.
*
* @template {AssetKind} K
* @param {Baggage} issuerBaggage
* @param {import('@agoric/vat-data').Baggage} issuerBaggage
* @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
Expand All @@ -101,14 +98,15 @@ export const upgradeIssuerKit = (
optShutdownWithFailure = undefined,
) => {
const issuerRecord = issuerBaggage.get(INSTANCE_KEY);
return setupIssuerKit(issuerRecord, issuerBaggage, optShutdownWithFailure);
const issuerZone = makeDurableZone(issuerBaggage);
return setupIssuerKit(issuerRecord, issuerZone, optShutdownWithFailure);
};
harden(upgradeIssuerKit);

/**
* Does baggage already have an issuerKit?
*
* @param {Baggage} baggage
* @param {import('@agoric/vat-data').Baggage} baggage
*/
export const hasIssuer = baggage => baggage.has(INSTANCE_KEY);

Expand Down Expand Up @@ -142,7 +140,7 @@ export const hasIssuer = baggage => baggage.has(INSTANCE_KEY);
* basic fungible tokens.
*
* `displayInfo` gives information to the UI on how to display the amount.
* @param {Baggage} issuerBaggage
* @param {import('@agoric/vat-data').Baggage} issuerBaggage
* @param {string} name
* @param {K} [assetKind]
* @param {AdditionalDisplayInfo} [displayInfo]
Expand All @@ -167,7 +165,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);

Expand All @@ -187,7 +186,7 @@ harden(makeDurableIssuerKit);
* basic fungible tokens.
*
* `displayInfo` gives information to the UI on how to display the amount.
* @param {Baggage} issuerBaggage
* @param {import('@agoric/vat-data').Baggage} issuerBaggage
* @param {string} name
* @param {K} [assetKind]
* @param {AdditionalDisplayInfo} [displayInfo]
Expand Down
4 changes: 2 additions & 2 deletions packages/ERTP/src/mathHelpers/copyBagMathHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import {
} from '@agoric/store';
import '../types-ambient.js';

/** @type {CopyBag} */
/** @type {import('@endo/patterns').CopyBag} */
const empty = makeCopyBag([]);

/** @type {MathHelpers<CopyBag>} */
/** @type {MathHelpers<import('@endo/patterns').CopyBag>} */
export const copyBagMathHelpers = harden({
doCoerce: bag => {
mustMatch(bag, M.bag(), 'bag of amount');
Expand Down
18 changes: 5 additions & 13 deletions packages/ERTP/src/payment.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
// @jessie-check

import { initEmpty } from '@agoric/store';
import { prepareExoClass } from '@agoric/vat-data';

/** @typedef {import('@endo/patterns').MethodGuard} MethodGuard */
/**
* @template {Record<string | symbol, MethodGuard>} [T=Record<string | symbol, MethodGuard>]
* @typedef {import('@endo/patterns').InterfaceGuard<T>} InterfaceGuard
*/
/** @typedef {import('@agoric/vat-data').Baggage} Baggage */

// TODO Type InterfaceGuard better than InterfaceGuard<any>
/**
* @template {AssetKind} K
* @param {Baggage} issuerBaggage
* @param {import('@agoric/zone').Zone} issuerZone
* @param {string} name
* @param {Brand<K>} brand
* @param {InterfaceGuard} PaymentI
* @param {import('@endo/patterns').InterfaceGuard<any>} PaymentI
* @returns {() => Payment<K>}
*/
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,
Expand Down
64 changes: 34 additions & 30 deletions packages/ERTP/src/paymentLedger.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,13 @@
/* 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 { AmountMath } from './amountMath.js';
import { preparePaymentKind } from './payment.js';
import { preparePurseKind } from './purse.js';

import '@agoric/store/exported.js';
import { BrandI, makeIssuerInterfaces } from './typeGuards.js';

/** @typedef {import('@agoric/vat-data').Baggage} Baggage */

const { details: X, quote: q, Fail } = assert;

/**
Expand Down Expand Up @@ -74,7 +67,7 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => {
* 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<K>} displayInfo
Expand All @@ -83,16 +76,20 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => {
* @returns {PaymentLedger<K>}
*/
export const preparePaymentLedger = (
issuerBaggage,
issuerZone,
name,
assetKind,
displayInfo,
elementShape,
optShutdownWithFailure = undefined,
) => {
/** @type {Brand<K>} */
// @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;
Expand Down Expand Up @@ -121,7 +118,7 @@ export const preparePaymentLedger = (
amountShape,
);

const makePayment = preparePaymentKind(issuerBaggage, name, brand, PaymentI);
const makePayment = preparePaymentKind(issuerZone, name, brand, PaymentI);

/** @type {ShutdownWithFailure} */
const shutdownLedgerWithFailure = reason => {
Expand All @@ -139,11 +136,9 @@ export const preparePaymentLedger = (
};

/** @type {WeakMapStore<Payment, Amount>} */
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 the purse
Expand All @@ -164,10 +159,7 @@ export const preparePaymentLedger = (
*
* @type {WeakMapStore<Payment, SetStore<Payment>>}
*/
const paymentRecoverySets = provideDurableWeakMapStore(
issuerBaggage,
'paymentRecoverySets',
);
const paymentRecoverySets = issuerZone.weakMapStore('paymentRecoverySets');

/**
* To maintain the invariants listed in the `paymentRecoverySets` comment,
Expand Down Expand Up @@ -293,7 +285,7 @@ export const preparePaymentLedger = (
/** @type {() => Purse<K>} */
// @ts-expect-error type parameter confusion
const makeEmptyPurse = preparePurseKind(
issuerBaggage,
issuerZone,
name,
assetKind,
brand,
Expand All @@ -305,8 +297,12 @@ export const preparePaymentLedger = (
);

/** @type {Issuer<K>} */
// @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;
},
Expand Down Expand Up @@ -359,20 +355,28 @@ export const preparePaymentLedger = (
* 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<K>}
*/
const mintRecoveryPurse = provide(issuerBaggage, 'mintRecoveryPurse', () =>
makeEmptyPurse(),
// Should be
// at-ts-expect-error checked cast
// but ran into the usual disagreement between local lint and IDE lint.
// Don't know yet about lint under CI.
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
// @ts-ignore
const mintRecoveryPurse = /** @type {Purse<K>} */ (
issuerZone.makeOnce('mintRecoveryPurse', () => makeEmptyPurse())
);

/** @type {Mint<K>} */
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
Expand Down
22 changes: 8 additions & 14 deletions packages/ERTP/src/purse.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
import { M } from '@agoric/store';
import { prepareExoClassKit, makeScalarBigSetStore } from '@agoric/vat-data';
import { AmountMath } from './amountMath.js';
import { makeTransientNotifierKit } from './transientNotifier.js';
import { makeAmountStore } from './amountStore.js';

// TODO `InterfaceGuard` type parameter
/** @typedef {import('@endo/patterns').InterfaceGuard} InterfaceGuard */
/** @typedef {import('@agoric/vat-data').Baggage} Baggage */

const { Fail } = assert;

// TODO Type InterfaceGuard better than InterfaceGuard<any>
/**
* @param {Baggage} issuerBaggage
* @param {import('@agoric/zone').Zone} issuerZone
* @param {string} name
* @param {AssetKind} assetKind
* @param {Brand} brand
* @param {{
* purse: InterfaceGuard;
* depositFacet: InterfaceGuard;
* purse: import('@endo/patterns').InterfaceGuard<any>;
* depositFacet: import('@endo/patterns').InterfaceGuard<any>;
* }} PurseIKit
* @param {{
* depositInternal: any;
* withdrawInternal: any;
* }} purseMethods
*/
export const preparePurseKind = (
issuerBaggage,
issuerZone,
name,
assetKind,
brand,
Expand All @@ -36,6 +32,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();

// - This kind is a pair of purse and depositFacet that have a 1:1
Expand All @@ -45,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<Payment>} */
const recoverySet = makeScalarBigSetStore('recovery set', {
durable: true,
});
const recoverySet = issuerZone.detached().setStore('recovery set');

return {
currentBalance,
Expand Down
Loading

0 comments on commit be6d970

Please sign in to comment.