Skip to content

Commit

Permalink
fix(smartWallet): handle upgrade disconnects from purse notifiers
Browse files Browse the repository at this point in the history
observeNotifier() would handle upgrade disconnects if the notifiers
were durable. But in @agoric/ertp, they're ephemeral, so we open-code
the loop.
  • Loading branch information
dckc committed Nov 28, 2023
1 parent f6268ae commit 8e5c74e
Showing 1 changed file with 33 additions and 20 deletions.
53 changes: 33 additions & 20 deletions packages/smart-wallet/src/smartWallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
prepareRecorderKit,
} from '@agoric/zoe/src/contractSupport/index.js';
import { E } from '@endo/far';
import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';

import { makeInvitationsHelper } from './invitations.js';
import { makeOfferExecutor } from './offers.js';
import { shape } from './typeGuards.js';
Expand Down Expand Up @@ -418,29 +420,40 @@ export const prepareSmartWallet = (baggage, shared) => {
/** @type {(purse: ERef<RemotePurse>) => Promise<void>} */
async watchPurse(purseRef) {
const { address } = this.state;
const { helper } = this.facets;

const purse = await purseRef; // promises don't fit in durable storage

const { helper } = this.facets;
// publish purse's balance and changes
void E.when(
E(purse).getCurrentAmount(),
balance => helper.updateBalance(purse, balance),
err =>
console.error(
address,
'initial purse balance publish failed',
err,
),
);
void observeNotifier(E(purse).getCurrentAmountNotifier(), {
updateState(balance) {
helper.updateBalance(purse, balance);
},
fail(reason) {
console.error(address, `failed updateState observer`, reason);
},
});
// This would seem to fit the observeNotifier() pattern,
// but purse notifiers are not (always) durable.
// outer loop: for each upgrade disconnection...
for (;;) {
const notifier = E(purse).getCurrentAmountNotifier();
let count;
// for each balance update
for (;;) {
try {
const { value: balance, updateCount } =
// eslint-disable-next-line no-await-in-loop
await E(notifier).getUpdateSince(count);
count = updateCount;
helper.updateBalance(purse, balance);
// final update
if (updateCount === undefined) {
return;
}
} catch (err) {
if (isUpgradeDisconnection(err)) {
break;
}
console.error(
`*** ${address} failed amount observer, ${err} ***`,
);
// TODO: think about API change.
throw err;
}
}
}
},

/**
Expand Down

0 comments on commit 8e5c74e

Please sign in to comment.