Skip to content

Commit

Permalink
Merge pull request #8562 from Agoric/sam/casting-capdata-errors
Browse files Browse the repository at this point in the history
fix(casting): dont crash on bad capdata
  • Loading branch information
mergify[bot] authored and mhofman committed Dec 6, 2023
2 parents b9d5f83 + 3f01369 commit a126c15
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 9 deletions.
7 changes: 7 additions & 0 deletions packages/agoric-cli/src/lib/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ export const coalesceWalletState = async (follower, invitationBrand) => {
// values with oldest last
const history = [];
for await (const followerElement of iterateReverse(follower)) {
if ('error' in followerElement) {
console.error(
'Skipping wallet update due to error:',
followerElement.error,
);
continue;
}
history.push(followerElement.value);
}

Expand Down
15 changes: 10 additions & 5 deletions packages/casting/src/follower-cosmjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,11 +330,16 @@ export const makeCosmjsFollower = (
blockHeight,
currentBlockHeight,
) => {
// AWAIT
const value = await /** @type {T} */ (
unserializer ? E(unserializer).fromCapData(data) : data
);
return { value, blockHeight, currentBlockHeight };
await null;
try {
// AWAIT
const value = await /** @type {T} */ (
unserializer ? E(unserializer).fromCapData(data) : data
);
return { value, blockHeight, currentBlockHeight };
} catch (e) {
return { blockHeight, currentBlockHeight, error: e, value: undefined };
}
};

/**
Expand Down
11 changes: 7 additions & 4 deletions packages/casting/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ export {};
*/

/**
* @see {ChangeFollower}
* @template T
* @typedef {object} ValueFollowerElement
* @property {T} value
* @typedef {object} ValueFollowerBase
* @property {number} blockHeight
* @property {number} currentBlockHeight
*/

/**
* @see {ChangeFollower}
* @template T
* @typedef {ValueFollowerBase & ({ value: T } | { value: undefined, error: any })} ValueFollowerElement
*/

/**
* @typedef {Pick<import('@endo/marshal').Marshal<unknown>, 'fromCapData' | 'unserialize'>} Unserializer
*/
Expand Down
56 changes: 56 additions & 0 deletions packages/casting/test/test-mvp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// @ts-nocheck
// eslint-disable-next-line import/order
import './lockdown.js';

import { makeMarshal } from '@endo/marshal';
import { test } from './prepare-test-env-ava.js';

import {
Expand Down Expand Up @@ -167,6 +170,59 @@ test('unrecognized proof', async t => {
);
});

test('yields error on bad capdata without terminating', async t => {
const marshal = makeMarshal();
const improperlyMarshalledData = { bad: 'data' };
const properlyMarshalledData = { foo: 'bar' };
const fakeValues = [
improperlyMarshalledData,
marshal.toCapData(harden(properlyMarshalledData)),
];
t.plan(4);
const options = { batchSize: 1, marshaller: { toCapData: data => data } };
const { controller, PORT } = await t.context.startFakeServer(
t,
fakeValues,
options,
);
controller.advance(0);
/** @type {import('../src/types.js').LeaderOptions} */
const lo = {
retryCallback: null, // fail fast, no retries
keepPolling: () => delay(1000).then(() => true), // poll really quickly
jitter: null, // no jitter
};
/** @type {import('../src/types.js').FollowerOptions} */
const so = {
proof: 'none',
};

const leader = makeLeader(`http://localhost:${PORT}/network-config`, lo);
const castingSpec = makeCastingSpec(':mailbox.agoric1foobarbaz');
const follower = await makeFollower(castingSpec, leader, so);
let i = 0;
// eslint-disable-next-line no-unreachable-loop
for await (const { value, error } of iterateEach(follower)) {
if (i === 0) {
t.log(`value from follower, should be undefined:`, value);
t.log(`error from follower, should be defined:`, error);

t.deepEqual(value, undefined);
t.assert(typeof error === 'object');

i += 1;
controller.advance(1);
} else if (i === 1) {
t.log(`value from follower, should be defined:`, value);
t.log(`error from follower, should be undefined:`, error);

t.deepEqual(value, properlyMarshalledData);
t.deepEqual(error, undefined);
break;
}
}
});

test.before(t => {
t.context.cleanups = [];
t.context.startFakeServer = startFakeServer;
Expand Down

0 comments on commit a126c15

Please sign in to comment.