Skip to content

Commit fb41e57

Browse files
authored
Release pending account on flow start (#12497)
closes: https://github.com/Agoric/agoric-private/issues/774 ## Description To accommodate stuck flows or flows that exit early before their make account resolve, forcibly mark any pending account as released when a new flow starts. This is safe because multiple active flows are not supposed to overlap. ### Security Considerations If by some misfortune multiple flows end up running concurrently, there is a risk that they could end up overwriting each other's generated account info. The EVM account info generation is idempotent, but the noble and agoric ones are not. For this reason we only release evm accounts. ### Scaling Considerations This will cause EVM account to be recreated, which is idempotent, but may consume gas. ### Documentation Considerations None ### Testing Considerations Reproduced the production situation that encountered this case in a contract test Added unit test of this behavior as well ### Upgrade Considerations This change being purely on the exo side is upgrade compatible.
2 parents e3099cb + d680fe8 commit fb41e57

File tree

6 files changed

+1443
-121
lines changed

6 files changed

+1443
-121
lines changed

packages/portfolio-contract/src/portfolio.exo.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,12 +597,29 @@ export const preparePortfolioKit = (
597597
* NB: `flowId` is a counter, not the key in vstorage.
598598
*/
599599
startFlow(detail: FlowDetail, steps?: MovementDesc[]) {
600-
const { nextFlowId: flowId, flowsRunning } = this.state;
600+
const {
601+
nextFlowId: flowId,
602+
flowsRunning,
603+
accountsPending,
604+
} = this.state;
601605
this.state.nextFlowId = flowId + 1;
602606
const sync: VowKit<MovementDesc[]> = vowTools.makeVowKit();
603607
if (steps) sync.resolver.resolve(steps);
604608
flowsRunning.init(flowId, harden({ sync, ...detail }));
605609
this.facets.reporter.publishStatus();
610+
if (accountsPending.getSize() > 0) {
611+
const traceFlow = trace
612+
.sub(`portfolio${this.state.portfolioId}`)
613+
.sub(`flow${flowId}`);
614+
const evmPendingAccounts = [...accountsPending.keys()].filter(
615+
chain => chain in AxelarChain,
616+
);
617+
traceFlow(`releasing pending evm accounts`, evmPendingAccounts);
618+
const reason = Error('starting new flow');
619+
for (const chainName of evmPendingAccounts) {
620+
this.facets.manager.releaseAccount(chainName, reason);
621+
}
622+
}
606623
return { stepsP: sync.vow, flowId };
607624
},
608625
providePosition(

packages/portfolio-contract/test/mocks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,14 @@ export const makeCCTPTraffic = (
228228
money = `${3_333.33 * 1000000}`,
229229
// This default matches the predicted addresss computed during tests
230230
dest = '0x8fcc8340520552c3cc861acaaa752e2d38bff2bb',
231+
destinationDomain = 3,
231232
) => ({
232233
depositForBurn: {
233234
msg: buildTxPacketString([
234235
MsgDepositForBurn.toProtoMsg({
235236
amount: money,
236237
burnToken: 'uusdc',
237-
destinationDomain: 3,
238+
destinationDomain,
238239
from,
239240
mintRecipient: leftPadEthAddressTo32Bytes(dest),
240241
}),

0 commit comments

Comments
 (0)