Skip to content

Commit

Permalink
fix: start on zonifying ertp
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed May 10, 2023
1 parent fb0def0 commit c5b54db
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 47 deletions.
1 change: 1 addition & 0 deletions packages/ERTP/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 9 additions & 5 deletions packages/ERTP/src/issuerKit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
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';

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

/**
Expand All @@ -24,7 +26,7 @@ import './types-ambient.js';
/**
* @template {AssetKind} K
* @param {IssuerRecord<K>} 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
Expand All @@ -36,7 +38,7 @@ import './types-ambient.js';
*/
const setupIssuerKit = (
{ name, assetKind, displayInfo, elementShape },
issuerBaggage,
issuerZone,
optShutdownWithFailure = undefined,
) => {
assert.typeof(name, 'string');
Expand All @@ -56,7 +58,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 Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down
10 changes: 4 additions & 6 deletions packages/ERTP/src/payment.js
Original file line number Diff line number Diff line change
@@ -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<K>} brand
* @param {InterfaceGuard} 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
72 changes: 43 additions & 29 deletions packages/ERTP/src/paymentLedger.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
/* 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';

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;

Expand Down Expand Up @@ -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<K>} displayInfo
Expand All @@ -83,16 +79,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 +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 => {
Expand All @@ -139,11 +139,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
Expand All @@ -165,10 +163,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 @@ -315,7 +310,7 @@ export const preparePaymentLedger = (
};

const makeEmptyPurse = preparePurseKind(
issuerBaggage,
issuerZone,
name,
assetKind,
brand,
Expand All @@ -327,8 +322,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 @@ -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<K>}
*/
const mintRecoveryPurse = provide(issuerBaggage, 'mintRecoveryPurse', () =>
makeEmptyPurse(),
const mintRecoveryPurse = /** @type {Purse<K>} */ (
provideFromZone(issuerZone, '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: 15 additions & 7 deletions packages/ERTP/src/purse.js
Original file line number Diff line number Diff line change
@@ -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<string, InterfaceGuard>} PurseIKit
* @param {Record<string, Callable>} purseMethods
*/
export const preparePurseKind = (
issuerBaggage,
issuerZone,
name,
assetKind,
brand,
Expand All @@ -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) => {
Expand All @@ -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<Payment>} */
const recoverySet = makeScalarBigSetStore('recovery set', {
durable: true,
});
const recoverySet = issuerZone.detached().setStore('recovery set');

return {
currentBalance,
Expand Down
2 changes: 2 additions & 0 deletions packages/ERTP/src/transientNotifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down

0 comments on commit c5b54db

Please sign in to comment.