Skip to content

Commit

Permalink
feat: make vat-localchain resumable (#9488)
Browse files Browse the repository at this point in the history
closes: #9484 closes: #9497

## Description

 - Changes the type of every return in `localchain.js` to `PromiseVow`
 - Uses `watch` for `.query()` and `.deposit()` methods and returns a `Vow`
 - Updates call sites outside `vat-localchain` to expect and unwrap PromiseVows (using `V`) 

### Upgrade Considerations

These changes better prepare us for upgrades - consumers will know to expect a `PromiseVow`.
  • Loading branch information
mergify[bot] authored and mhofman committed Jun 20, 2024
2 parents 424e490 + c48a72d commit f3669dc
Show file tree
Hide file tree
Showing 16 changed files with 356 additions and 216 deletions.
11 changes: 9 additions & 2 deletions packages/boot/test/bootstrapTests/ibcClientMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { Far } from '@endo/far';
import { V as E } from '@agoric/vow/vat.js';

/**
* @import {ListenHandler, PortAllocator} from '@agoric/network';
* @import {Connection, PortAllocator} from '@agoric/network';
* @import {FarRef, ERef} from '@agoric/vow';
*/

/**
* @param {ZCF} zcf
* @param {{
* portAllocator: ERef<PortAllocator>;
* portAllocator: FarRef<PortAllocator>;
* }} privateArgs
* @param {import('@agoric/vat-data').Baggage} _baggage
*/
Expand All @@ -20,7 +21,13 @@ export const start = async (zcf, privateArgs, _baggage) => {
const myPort = await E(portAllocator).allocateCustomIBCPort();

const { log } = console;
/**
* @type {FarRef<Connection>}
*/
let connP;
/**
* @type {ERef<string>}
*/
let ackP;

const creatorFacet = Far('CF', {
Expand Down
10 changes: 9 additions & 1 deletion packages/internal/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable max-classes-per-file */
import type { RemotableBrand } from '@endo/eventual-send';
import type { ERef, RemotableBrand } from '@endo/eventual-send';
import type { Primitive } from '@endo/pass-style';
import type { Callable } from './utils.js';

Expand Down Expand Up @@ -56,3 +56,11 @@ export type DataOnly<T> =
export type Remote<Primary, Local = DataOnly<Primary>> =
| Primary
| RemotableBrand<Local, Primary>;

// TODO: Add type tests for FarRef and Remote.
/**
* Potentially remote promises or settled references.
*/
export type FarRef<Primary, Local = DataOnly<Primary>> = ERef<
Remote<Primary, Local>
>;
8 changes: 4 additions & 4 deletions packages/network/src/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ export const preparePortAllocator = (zone, { watch }) =>
*/
({ protocol }) => ({ protocol, lastICAPortNum: 0n, lastICQPortNum: 0n }),
{
allocateCustomIBCPort(specifiedName = '') {
async allocateCustomIBCPort(specifiedName = '') {
const { state } = this;
let localAddr = `/ibc-port/`;

Expand All @@ -1488,7 +1488,7 @@ export const preparePortAllocator = (zone, { watch }) =>
// Allocate an IBC port with a unique generated name.
return watch(E(state.protocol).bindPort(localAddr));
},
allocateICAControllerPort() {
async allocateICAControllerPort() {
const { state } = this;
state.lastICAPortNum += 1n;
return watch(
Expand All @@ -1497,7 +1497,7 @@ export const preparePortAllocator = (zone, { watch }) =>
),
);
},
allocateICQControllerPort() {
async allocateICQControllerPort() {
const { state } = this;
state.lastICQPortNum += 1n;
return watch(
Expand All @@ -1506,7 +1506,7 @@ export const preparePortAllocator = (zone, { watch }) =>
),
);
},
allocateCustomLocalPort(specifiedName = '') {
async allocateCustomLocalPort(specifiedName = '') {
const { state } = this;

let localAddr = `/local/`;
Expand Down
18 changes: 10 additions & 8 deletions packages/orchestration/src/examples/stakeBld.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/record
import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js';
import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
import { makeDurableZone } from '@agoric/zone/durable.js';
import { V } from '@agoric/vow/vat.js';
import { E } from '@endo/far';
import { deeplyFulfilled } from '@endo/marshal';
import { M } from '@endo/patterns';
Expand Down Expand Up @@ -33,11 +34,6 @@ const trace = makeTracer('StakeBld');
* @param {import('@agoric/vat-data').Baggage} baggage
*/
export const start = async (zcf, privateArgs, baggage) => {
const BLD = zcf.getTerms().brands.In;

// XXX is this safe to call before prepare statements are completed?
const bldAmountShape = await E(BLD).getAmountShape();

const zone = makeDurableZone(baggage);

const { makeRecorderKit } = prepareRecorderKitMakers(
Expand All @@ -53,9 +49,15 @@ export const start = async (zcf, privateArgs, baggage) => {
makeChainHub(privateArgs.agoricNames),
);

// ----------------
// All `prepare*` calls should go above this line.

const BLD = zcf.getTerms().brands.In;
const bldAmountShape = await E(BLD).getAmountShape();

async function makeLocalAccountKit() {
const account = await E(privateArgs.localchain).makeAccount();
const address = await E(account).getAddress();
const account = await V(privateArgs.localchain).makeAccount();
const address = await V(account).getAddress();
// XXX 'address' is implied by 'account'; use an async maker that get the value itself
return makeLocalChainAccountKit({
account,
Expand Down Expand Up @@ -84,7 +86,7 @@ export const start = async (zcf, privateArgs, baggage) => {
const { In } = await deeplyFulfilled(
withdrawFromSeat(zcf, seat, give),
);
await E(holder).deposit(In);
await V(holder).deposit(In);
seat.exit();
return harden({
publicSubscribers: holder.getPublicTopics(),
Expand Down
17 changes: 9 additions & 8 deletions packages/orchestration/src/exos/local-chain-account-kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { makeTracer } from '@agoric/internal';
import { M } from '@agoric/vat-data';
import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/index.js';
import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
import { V } from '@agoric/vow/vat.js';
import { E } from '@endo/far';
import {
AmountArgShape,
Expand Down Expand Up @@ -159,9 +160,9 @@ export const prepareLocalChainAccountKit = (
};
const { account: lca } = this.state;
trace('lca', lca);
const delegatorAddress = await E(lca).getAddress();
const delegatorAddress = await V(lca).getAddress();
trace('delegatorAddress', delegatorAddress);
const [result] = await E(lca).executeTx([
const [result] = await V(lca).executeTx([
typedJson('/cosmos.staking.v1beta1.MsgDelegate', {
amount,
validatorAddress,
Expand All @@ -184,9 +185,9 @@ export const prepareLocalChainAccountKit = (
};
const { account: lca } = this.state;
trace('lca', lca);
const delegatorAddress = await E(lca).getAddress();
const delegatorAddress = await V(lca).getAddress();
trace('delegatorAddress', delegatorAddress);
const [response] = await E(lca).executeTx([
const [response] = await V(lca).executeTx([
typedJson('/cosmos.staking.v1beta1.MsgUndelegate', {
amount,
validatorAddress,
Expand All @@ -208,16 +209,16 @@ export const prepareLocalChainAccountKit = (
*/
/** @type {LocalChainAccount['deposit']} */
async deposit(payment, optAmountShape) {
return E(this.state.account).deposit(payment, optAmountShape);
return V(this.state.account).deposit(payment, optAmountShape);
},
/** @type {LocalChainAccount['withdraw']} */
async withdraw(amount) {
return E(this.state.account).withdraw(amount);
return V(this.state.account).withdraw(amount);
},
/** @type {LocalChainAccount['executeTx']} */
async executeTx(messages) {
// @ts-expect-error subtype
return E(this.state.account).executeTx(messages);
return V(this.state.account).executeTx(messages);
},
/** @returns {ChainAddress['address']} */
getAddress() {
Expand Down Expand Up @@ -252,7 +253,7 @@ export const prepareLocalChainAccountKit = (
? 0n
: await timestampHelper.getTimeoutTimestampNS());

const [result] = await E(this.state.account).executeTx([
const [result] = await V(this.state.account).executeTx([
typedJson('/ibc.applications.transfer.v1.MsgTransfer', {
sourcePort: transferChannel.portId,
sourceChannel: transferChannel.channelId,
Expand Down
2 changes: 1 addition & 1 deletion packages/orchestration/src/facade.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @file Orchestration service */

import { E } from '@endo/far';
import { V as E } from '@agoric/vow/vat.js';
import { prepareCosmosOrchestrationAccount } from './exos/cosmosOrchestrationAccount.js';

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { AmountMath } from '@agoric/ertp';
import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js';
import { V } from '@agoric/vow/vat.js';
import { E } from '@endo/far';
import path from 'path';
import { commonSetup } from '../supports.js';
Expand Down Expand Up @@ -53,15 +54,15 @@ test('makeAccount, deposit, withdraw', async t => {
t.regex(await E(account).getAddress(), /agoric1/);

t.log('deposit 100 bld to account');
const depositResp = await E(account).deposit(
const depositResp = await V(account).deposit(
await utils.pourPayment(bld.units(100)),
);
t.true(AmountMath.isEqual(depositResp, bld.units(100)), 'deposit');

// TODO validate balance, .getBalance()

t.log('withdraw bld from account');
const withdrawResp = await E(account).withdraw(bld.units(100));
const withdrawResp = await V(account).withdraw(bld.units(100));
const withdrawAmt = await bld.issuer.getAmountOf(withdrawResp);
t.true(AmountMath.isEqual(withdrawAmt, bld.units(100)), 'withdraw');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import { AmountMath } from '@agoric/ertp';
import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js';
import { E, Far } from '@endo/far';
import { V as E } from '@agoric/vow/vat.js';
import { Far } from '@endo/far';
import { commonSetup } from '../supports.js';
import { prepareLocalChainAccountKit } from '../../src/exos/local-chain-account-kit.js';
import { ChainAddress } from '../../src/orchestration-api.js';
Expand Down
5 changes: 4 additions & 1 deletion packages/orchestration/test/supports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ export const commonSetup = async t => {
}),
);

const vowTools = prepareVowTools(rootZone.subZone('vows'));

const transferBridge = makeFakeTransferBridge(rootZone);
const { makeBridgeTargetKit } = prepareBridgeTargetModule(
rootZone.subZone('bridge'),
);
const { makeTransferMiddlewareKit } = prepareTransferTools(
rootZone.subZone('transfer'),
prepareVowTools(rootZone.subZone('vows')),
vowTools,
);

const { finisher, interceptorFactory, transferMiddleware } =
Expand All @@ -90,6 +92,7 @@ export const commonSetup = async t => {
);
const localchain = prepareLocalChainTools(
rootZone.subZone('localchain'),
vowTools,
).makeLocalChain({
bankManager,
system: localchainBridge,
Expand Down
Loading

0 comments on commit f3669dc

Please sign in to comment.