Skip to content

Commit

Permalink
test: send-anywhere contract upgrade
Browse files Browse the repository at this point in the history
- no longer relies on buggy agoricNames
- continues to test async-flow resumability and cross-chain vow settlement across upgrade

Co-authored-by: 0xPatrick <[email protected]>
  • Loading branch information
iomekam and 0xpatrickdev committed Nov 29, 2024
1 parent f240dd5 commit 307700a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 183 deletions.
52 changes: 30 additions & 22 deletions packages/boot/test/orchestration/contract-upgrade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { TestFn } from 'ava';

import { BridgeId } from '@agoric/internal';
import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js';
import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js';
import { withChainCapabilities } from '@agoric/orchestration';
import {
makeWalletFactoryContext,
type WalletFactoryTestContext,
Expand All @@ -19,17 +21,13 @@ test.before(async t => {
test.after.always(t => t.context.shutdown?.());

/**
* This test core-evals a buggy installation of the sendAnywhere contract by
* giving it a faulty `agoricNames` service with a lookup() function which
* returns a promise that never resolves.
* This test core-evals an installation of the sendAnywhere contract that
* initiates an IBC Transfer. Since that goes over a bridge and is tracked
* by a vow, we can restart the contract and see that the vow settles. We
* can manually trigger a bridge event in the testing context.
*
* Because the send-anywhere flow requires a lookup(), it waits forever. This
* gives us a point at which we can upgrade the vat with a working agoricNames
* and see that the flow continues from that point. (The lookup call is not made
* directly in a flow, but instead from a host API which uses the retryable
* helper. As such it tests both the idempotent retry mechanism of retryable on
* upgrades, and the ability to resume an async-flow for which a host vow
* settles after an upgrade.)
* As such, this demonstrates the ability to resume an async-flow for for which
* a host vow settles after an upgrade.
*/
test('resume', async t => {
const {
Expand All @@ -44,9 +42,21 @@ test('resume', async t => {

t.log('start sendAnywhere');
await evalProposal(
buildProposal(
'@agoric/builders/scripts/testing/start-buggy-sendAnywhere.js',
),
buildProposal('@agoric/builders/scripts/testing/init-send-anywhere.js', [
'--chainInfo',
JSON.stringify(withChainCapabilities(fetchedChainInfo)),
'--assetInfo',
JSON.stringify([
[
'uist',
{
baseDenom: 'uist',
baseName: 'agoric',
chainName: 'agoric',
},
],
]),
]),
);

t.log('making offer');
Expand All @@ -70,23 +80,21 @@ test('resume', async t => {

// XXX golden test
const getLogged = () =>
JSON.parse(storage.data.get('published.sendAnywhere.log')!).values;

// This log shows the flow started, but didn't get past the name lookup
t.deepEqual(getLogged(), ['sending {0} from cosmoshub to cosmos1whatever']);

t.log('upgrade sendAnywhere with fix');
await evalProposal(
buildProposal('@agoric/builders/scripts/testing/fix-buggy-sendAnywhere.js'),
);
JSON.parse(storage.data.get('published.send-anywhere.log')!).values;

// This log shows the flow started, but didn't get past the IBC Transfer settlement
t.deepEqual(getLogged(), [
'sending {0} from cosmoshub to cosmos1whatever',
'got info for denoms: ibc/FE98AAD68F02F03565E9FA39A5E627946699B2B07115889ED812D8BA639576A9, ibc/toyatom, ibc/toyusdc, ubld, uist',
'got info for chain: cosmoshub cosmoshub-4',
'completed transfer to localAccount',
]);

t.log('upgrade sendAnywhere with fix');
await evalProposal(
buildProposal('@agoric/builders/scripts/testing/upgrade-send-anywhere.js'),
);

// simulate ibc/MsgTransfer ack from remote chain, enabling `.transfer()` promise
// to resolve
await runInbound(
Expand Down
143 changes: 0 additions & 143 deletions packages/builders/scripts/testing/start-buggy-sendAnywhere.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
makeTracer,
NonNullish,
} from '@agoric/internal';
import { E, Far } from '@endo/far';
import { E } from '@endo/far';

/// <reference types="@agoric/vats/src/core/types-ambient"/>
/**
* @import {Installation, Instance} from '@agoric/zoe/src/zoeService/utils.js';
*/

const trace = makeTracer('FixBuggySA', true);
const trace = makeTracer('UpgradeSA', true);

/**
* @import {start as StartFn} from '@agoric/orchestration/src/examples/send-anywhere.contract.js';
Expand All @@ -30,7 +30,7 @@ const trace = makeTracer('FixBuggySA', true);
* }} powers
* @param {...any} rest
*/
export const fixSendAnywhere = async (
export const upgradeSendAnywhere = async (
{
consume: {
agoricNames,
Expand All @@ -45,50 +45,46 @@ export const fixSendAnywhere = async (
},
{ options: { sendAnywhereRef } },
) => {
trace(fixSendAnywhere.name);
trace(upgradeSendAnywhere.name);

const saInstance = await instances.consume.sendAnywhere;
trace('saInstance', saInstance);
const saKit = await E(contractKits).get(saInstance);

const marshaller = await E(board).getReadonlyMarshaller();

// This apparently pointless wrapper is to maintain structural parity
// with the buggy core-eval's wrapper to make lookup() hang.
const agoricNamesResolves = Far('agoricNames that resolves', {
lookup: async (...args) => {
return E(agoricNames).lookup(...args);
},
});

const privateArgs = await deeplyFulfilledObject(
harden({
agoricNames: agoricNamesResolves,
agoricNames,
localchain,
marshaller,
orchestrationService: cosmosInterchainService,
storageNode: E(NonNullish(await chainStorage)).makeChildNode(
'sendAnywhere',
'send-anywhere',
),
timerService: chainTimerService,
// undefined so `registerKnownChainsAndAssets` does not run again
chainInfo: undefined,
assetInfo: undefined,
}),
);

trace('upgrading...');
trace('ref', sendAnywhereRef);
await E(saKit.adminFacet).upgradeContract(
sendAnywhereRef.bundleID,
privateArgs,
);

trace('done');
};
harden(fixSendAnywhere);
harden(upgradeSendAnywhere);

export const getManifestForValueVow = ({ restoreRef }, { sendAnywhereRef }) => {
console.log('sendAnywhereRef', sendAnywhereRef);
return {
manifest: {
[fixSendAnywhere.name]: {
[upgradeSendAnywhere.name]: {
consume: {
agoricNames: true,
board: true,
Expand Down Expand Up @@ -120,7 +116,7 @@ export const getManifestForValueVow = ({ restoreRef }, { sendAnywhereRef }) => {
export const defaultProposalBuilder = async ({ publishRef, install }) =>
harden({
// Somewhat unorthodox, source the exports from this builder module
sourceSpec: '@agoric/builders/scripts/testing/fix-buggy-sendAnywhere.js',
sourceSpec: '@agoric/builders/scripts/testing/upgrade-send-anywhere.js',
getManifestCall: [
'getManifestForValueVow',
{
Expand All @@ -139,5 +135,5 @@ export default async (homeP, endowments) => {
const dspModule = await import('@agoric/deploy-script-support');
const { makeHelpers } = dspModule;
const { writeCoreEval } = await makeHelpers(homeP, endowments);
await writeCoreEval(fixSendAnywhere.name, defaultProposalBuilder);
await writeCoreEval(upgradeSendAnywhere.name, defaultProposalBuilder);
};

0 comments on commit 307700a

Please sign in to comment.