Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

10130 excise SharedStateRecord #10140

Merged
merged 3 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/async-flow/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './src/async-flow.js';
export * from './src/types-index.js';
export { makeSharedStateRecord } from './src/endowments.js';
32 changes: 0 additions & 32 deletions packages/async-flow/src/endowments.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,6 @@ export const forwardingMethods = rem => {
return fromEntries(keys.map(makeMethodEntry));
};

/**
* Given a possibly mutable (and therefore unhardened) record, return a
* corresponding state record that acts identically for normal
* gets and sets, but is implemented using accessors, so it will be recognized
* as a state record.
*
* @template { string | number | symbol } K
* @template {Record<K, any>} R
* @param {R} dataRecord
* @returns {R}
*/
export const makeSharedStateRecord = dataRecord =>
harden(
create(
objectPrototype,
fromEntries(
ownKeys(dataRecord).flatMap(key =>
entries(
getOwnPropertyDescriptors({
get [key]() {
return dataRecord[key];
},
set [key](newValue) {
dataRecord[key] = newValue;
},
}),
),
),
),
),
);

/**
* @param {Zone} outerZone
* @param {PreparationOptions} [outerOptions]
Expand Down
25 changes: 16 additions & 9 deletions packages/orchestration/src/examples/send-anywhere.contract.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { makeSharedStateRecord } from '@agoric/async-flow';

import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
import { E } from '@endo/far';
import { M } from '@endo/patterns';
import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js';
import { AnyNatAmountShape } from '../typeGuards.js';
import { withOrchestration } from '../utils/start-helper.js';
import * as flows from './send-anywhere.flows.js';
import * as sharedFlows from './shared.flows.js';

/**
* @import {Vow} from '@agoric/vow';
Expand Down Expand Up @@ -38,23 +37,31 @@ export const contract = async (
zone,
{ chainHub, orchestrateAll, vowTools, zoeTools },
) => {
const contractState = makeSharedStateRecord(
/** @type {{ account: OrchestrationAccount<any> | undefined }} */ {
localAccount: undefined,
},
);

const creatorFacet = prepareChainHubAdmin(zone, chainHub);

// UNTIL https://github.com/Agoric/agoric-sdk/issues/9066
const logNode = E(privateArgs.storageNode).makeChildNode('log');
/** @type {(msg: string) => Vow<void>} */
const log = msg => vowTools.watch(E(logNode).setValue(msg));

const { makeLocalAccount } = orchestrateAll(sharedFlows, {});
/**
* Setup a shared local account for use in async-flow functions. Typically,
* exo initState functions need to resolve synchronously, but `makeOnce`
* allows us to provide a Promise. When using this inside a flow, we must
* await it to ensure the account is available for use.
*
* @type {any} sharedLocalAccountP expects a Promise but this is a vow
* https://github.com/Agoric/agoric-sdk/issues/9822
*/
const sharedLocalAccountP = zone.makeOnce('localAccount', () =>
makeLocalAccount(),
);

// orchestrate uses the names on orchestrationFns to do a "prepare" of the associated behavior
const orchFns = orchestrateAll(flows, {
contractState,
log,
sharedLocalAccountP,
zoeTools,
});

Expand Down
23 changes: 12 additions & 11 deletions packages/orchestration/src/examples/send-anywhere.flows.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { M, mustMatch } from '@endo/patterns';
/**
* @import {GuestInterface, GuestOf} from '@agoric/async-flow';
* @import {Vow} from '@agoric/vow';
* @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js';
* @import {ZoeTools} from '../utils/zoe-tools.js';
* @import {Orchestrator, LocalAccountMethods, OrchestrationAccountI, OrchestrationFlow} from '../types.js';
* @import {Orchestrator, OrchestrationFlow, LocalAccountMethods} from '../types.js';
*/

const { entries } = Object;
Expand All @@ -18,15 +19,15 @@ const { entries } = Object;
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} orch
* @param {object} ctx
* @param {{ localAccount?: OrchestrationAccountI & LocalAccountMethods }} ctx.contractState
* @param {Promise<GuestInterface<LocalOrchestrationAccountKit['holder']>>} ctx.sharedLocalAccountP
* @param {GuestInterface<ZoeTools>} ctx.zoeTools
* @param {GuestOf<(msg: string) => Vow<void>>} ctx.log
* @param {ZCFSeat} seat
* @param {{ chainName: string; destAddr: string }} offerArgs
*/
export const sendIt = async (
orch,
{ contractState, log, zoeTools: { localTransfer, withdrawToSeat } },
{ sharedLocalAccountP, log, zoeTools: { localTransfer, withdrawToSeat } },
seat,
offerArgs,
) => {
Expand All @@ -44,23 +45,23 @@ export const sendIt = async (
`${amt.brand} not registered in vbank`,
);

// FIXME racy
if (!contractState.localAccount) {
contractState.localAccount = await agoric.makeAccount();
}

const chain = await orch.getChain(chainName);
const info = await chain.getChainInfo();
const { chainId } = info;
assert(typeof chainId === 'string', 'bad chainId');
void log(`got info for chain: ${chainName} ${chainId}`);

await localTransfer(seat, contractState.localAccount, give);
/**
* @type {any} XXX methods returning vows
* https://github.com/Agoric/agoric-sdk/issues/9822
*/
const sharedLocalAccount = await sharedLocalAccountP;
await localTransfer(seat, sharedLocalAccount, give);

void log(`completed transfer to localAccount`);

try {
await contractState.localAccount.transfer(
await sharedLocalAccount.transfer(
{
value: destAddr,
encoding: 'bech32',
Expand All @@ -70,7 +71,7 @@ export const sendIt = async (
);
void log(`completed transfer to ${destAddr}`);
} catch (e) {
await withdrawToSeat(contractState.localAccount, seat, give);
await withdrawToSeat(sharedLocalAccount, seat, give);
const errorMsg = `IBC Transfer failed ${q(e)}`;
void log(`ERROR: ${errorMsg}`);
seat.exit(errorMsg);
Expand Down
21 changes: 21 additions & 0 deletions packages/orchestration/src/examples/shared.flows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @file Flows shared by multiple examples
*
* A module with flows can be used be reused across multiple contracts. They are
* bound to a particular contract's context via orchestrateAll. See
* ./send-anywhere.contract.js for example usage.
*/
/**
* @import {Orchestrator, OrchestrationFlow, LocalAccountMethods} from '../types.js';
*/

/**
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} orch
* @returns {Promise<LocalAccountMethods>}
*/
export const makeLocalAccount = async orch => {
const agoricChain = await orch.getChain('agoric');
return agoricChain.makeAccount();
};
harden(makeLocalAccount);
2 changes: 2 additions & 0 deletions packages/orchestration/src/examples/stake-bld.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ export const start = async (zcf, privateArgs, baggage) => {
const { give } = seat.getProposal();
trace('makeStakeBldInvitation', give);
const { holder } = await makeLocalAccountKit();
/** @type {Record<string, Payment<'nat'>>} */
// @ts-expect-error XXX PaymentPKeywordRecord throught deeplyFulfilled will be a PaymnentKeywordRecord
const { In } = await deeplyFulfilled(
withdrawFromSeat(zcf, seat, give),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
* The primary offer result is a power for invitation makers that can perform
* actions with an ICA account.
*/
import { makeSharedStateRecord } from '@agoric/async-flow';
import { AmountShape } from '@agoric/ertp';
import { M } from '@endo/patterns';
import { prepareCombineInvitationMakers } from '../exos/combine-invitation-makers.js';
import { CosmosOrchestrationInvitationMakersI } from '../exos/cosmos-orchestration-account.js';
import { ChainAddressShape, DelegationShape } from '../typeGuards.js';
import { withOrchestration } from '../utils/start-helper.js';
import * as flows from './staking-combinations.flows.js';
import * as sharedFlows from './shared.flows.js';
import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js';

/**
Expand Down Expand Up @@ -46,16 +46,6 @@ const contract = async (
zone,
{ orchestrateAll, zoeTools, chainHub },
) => {
const contractState = makeSharedStateRecord(
/**
* @type {{
* account: (OrchestrationAccount<any> & LocalAccountMethods) | undefined;
* }}
*/ {
localAccount: undefined,
},
);

const StakingCombinationsInvitationMakersI = M.interface(
'StakingCombinationsInvitationMakersI',
{
Expand Down Expand Up @@ -128,8 +118,22 @@ const contract = async (
StakingCombinationsInvitationMakersI,
);

const { makeLocalAccount } = orchestrateAll(sharedFlows, {});
/**
* Setup a shared local account for use in async-flow functions. Typically,
* exo initState functions need to resolve synchronously, but `makeOnce`
* allows us to provide a Promise. When using this inside a flow, we must
* await it to ensure the account is available for use.
*
* @type {any} sharedLocalAccountP expects a Promise but this is a vow
* https://github.com/Agoric/agoric-sdk/issues/9822
*/
const sharedLocalAccountP = zone.makeOnce('localAccount', () =>
makeLocalAccount(),
);

const orchFns = orchestrateAll(flows, {
contractState,
sharedLocalAccountP,
makeCombineInvitationMakers,
makeExtraInvitationMaker,
flows,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @import {GuestInterface} from '@agoric/async-flow';
* @import {Orchestrator, OrchestrationFlow, AmountArg, CosmosValidatorAddress, ChainAddress, LocalAccountMethods, OrchestrationAccountI} from '../types.js'
* @import {ContinuingOfferResult, InvitationMakers} from '@agoric/smart-wallet/src/types.js';
* @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js';
* @import {MakeCombineInvitationMakers} from '../exos/combine-invitation-makers.js';
* @import {CosmosOrchestrationAccount} from '../exos/cosmos-orchestration-account.js';
* @import {ResolvedContinuingOfferResult, ZoeTools} from '../utils/zoe-tools.js';
Expand Down Expand Up @@ -47,7 +48,7 @@ harden(makeAccount);
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} orch
* @param {object} ctx
* @param {{ localAccount?: OrchestrationAccountI & LocalAccountMethods }} ctx.contractState
* @param {Promise<GuestInterface<LocalOrchestrationAccountKit['holder']>>} ctx.sharedLocalAccountP
* @param {GuestInterface<ZoeTools>} ctx.zoeTools
* @param {GuestInterface<CosmosOrchestrationAccount>} account
* @param {ZCFSeat} seat
Expand All @@ -56,26 +57,28 @@ harden(makeAccount);
*/
export const depositAndDelegate = async (
orch,
{ contractState, zoeTools },
{ sharedLocalAccountP, zoeTools },
account,
seat,
validator,
) => {
await null;
trace('depositAndDelegate', account, seat, validator);
mustMatch(validator, ChainAddressShape);
if (!contractState.localAccount) {
const agoricChain = await orch.getChain('agoric');
contractState.localAccount = await agoricChain.makeAccount();
}

const { give } = seat.getProposal();
await zoeTools.localTransfer(seat, contractState.localAccount, give);
/**
* @type {any} XXX methods returning vows
* https://github.com/Agoric/agoric-sdk/issues/9822
*/
const sharedLocalAccount = await sharedLocalAccountP;
await zoeTools.localTransfer(seat, sharedLocalAccount, give);

const address = account.getAddress();
try {
await contractState.localAccount.transfer(address, give.Stake);
await sharedLocalAccount.transfer(address, give.Stake);
} catch (cause) {
await zoeTools.withdrawToSeat(contractState.localAccount, seat, give);
await zoeTools.withdrawToSeat(sharedLocalAccount, seat, give);
const errMsg = makeError(`ibc transfer failed ${q(cause)}`);
seat.exit(errMsg);
throw errMsg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { coerceCoin, coerceDenomAmount } from '../utils/amounts.js';
/**
* @import {HostOf} from '@agoric/async-flow';
* @import {LocalChain, LocalChainAccount} from '@agoric/vats/src/localchain.js';
* @import {AmountArg, ChainAddress, DenomAmount, IBCMsgTransferOptions, IBCConnectionInfo, OrchestrationAccountI} from '@agoric/orchestration';
* @import {AmountArg, ChainAddress, DenomAmount, IBCMsgTransferOptions, IBCConnectionInfo, OrchestrationAccountI, LocalAccountMethods} from '@agoric/orchestration';
* @import {RecorderKit, MakeRecorderKit} from '@agoric/zoe/src/contractSupport/recorder.js'.
* @import {Zone} from '@agoric/zone';
* @import {Remote} from '@agoric/internal';
Expand Down Expand Up @@ -613,14 +613,14 @@ export const prepareLocalOrchestrationAccountKit = (
* updater will get a special notification that the account is being
* transferred.
*/
/** @type {HostOf<LocalChainAccount['deposit']>} */
/** @type {HostOf<LocalAccountMethods['deposit']>} */
deposit(payment) {
return watch(
E(this.state.account).deposit(payment),
this.facets.returnVoidWatcher,
);
},
/** @type {HostOf<LocalChainAccount['withdraw']>} */
/** @type {HostOf<LocalAccountMethods['withdraw']>} */
withdraw(amount) {
return watch(E(this.state.account).withdraw(amount));
},
Expand Down Expand Up @@ -733,7 +733,7 @@ export const prepareLocalOrchestrationAccountKit = (
matchFirstPacket(patternV) {
return watch(E(this.state.packetTools).matchFirstPacket(patternV));
},
/** @type {HostOf<LocalChainAccount['monitorTransfers']>} */
/** @type {HostOf<LocalAccountMethods['monitorTransfers']>} */
monitorTransfers(tap) {
return watch(E(this.state.packetTools).monitorTransfers(tap));
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,30 @@ Generated by [AVA](https://avajs.dev).
FunctionUnwrapper_singleton: 'Alleged: FunctionUnwrapper',
LogStore_kindHandle: 'Alleged: kind',
StateUnwrapper_kindHandle: 'Alleged: kind',
asyncFuncEagerWakers: [],
asyncFuncEagerWakers: [
Object @Alleged: asyncFlow flow {},
],
asyncFuncFailures: {},
flowForOutcomeVow: {},
flowForOutcomeVow: {
'Alleged: VowInternalsKit vowV0': 'Alleged: asyncFlow flow',
},
unwrapMap: 'Alleged: weakMapStore',
},
chainHub: {
ChainHub_kindHandle: 'Alleged: kind',
ChainHub_singleton: 'Alleged: ChainHub',
brandDenom: {},
chainInfos: {},
chainInfos: {
agoric: {
chainId: 'agoric-3',
icqEnabled: false,
stakingTokens: [
{
denom: 'ubld',
},
],
},
},
connectionInfos: {},
denom: {},
lookupChainInfo_kindHandle: 'Alleged: kind',
Expand All @@ -40,13 +54,15 @@ Generated by [AVA](https://avajs.dev).
'ChainHub Admin_singleton': 'Alleged: ChainHub Admin',
'Send PF_kindHandle': 'Alleged: kind',
'Send PF_singleton': 'Alleged: Send PF',
localAccount: 'Vow',
orchestration: {
makeLocalAccount: {
asyncFlow_kindHandle: 'Alleged: kind',
},
sendIt: {
asyncFlow_kindHandle: 'Alleged: kind',
endowments: {
0: {
contractState_kindHandle: 'Alleged: kind',
contractState_singleton: 'Alleged: contractState',
log_kindHandle: 'Alleged: kind',
log_singleton: 'Alleged: log',
zoeTools: {
Expand Down
Binary file not shown.
Loading
Loading