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

feat(extract-proposal): organize proposals into steps #8370

Merged
merged 4 commits into from
Jan 23, 2024

Conversation

michaelfig
Copy link
Member

@michaelfig michaelfig commented Sep 22, 2023

refs: #8219
related: #8441

Description

Given coreProposals: ParallelProposals | { steps: ParallelProposals[] } (with typedef ParallelProposals = Proposal[]), return codeSteps: string[] from extractCoreProposalBundles. Then execute each ParallelProposals in parallel, fully draining the kernel run queue before proceeding to the next step.

Security Considerations

n/a

Scaling Considerations

n/a

Documentation Considerations

Would be useful to document the coreProposals mechanism and call out the meaning of .steps fields if present.

Testing Considerations

Tested with packages/cosmic-swingset/economy-template.json.

Upgrade Considerations

Makes coreProposals processing more flexible than simply evaluating all of them in parallel.

@michaelfig michaelfig marked this pull request as draft September 22, 2023 01:15
@michaelfig michaelfig changed the title Mfig core proposal deps feat(extract-proposal): named proposals with expressed needs Sep 22, 2023
@michaelfig michaelfig self-assigned this Sep 22, 2023
@michaelfig michaelfig added the cosmic-swingset package: cosmic-swingset label Sep 22, 2023
@michaelfig michaelfig marked this pull request as ready for review September 22, 2023 17:17
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only done a partial review, and have not yet reviewed the graph resolver itself.

Mostly nits, except for the context of separately injected core evals which needs to be different.

Potential for deadlock if core proposals have .needs that don't actually provide the functionality needed by the dependent to make progress.

This seems formulated backward. Did you mean that a dependent forgot to include some entry in its .needs, or did I misunderstand?

I'm also unclear about 2 things:

  • Since we're going from an array to an object for the definitions, in what order are individual core evals executed if the proposals have no needs?
  • How are cyclical needs resolved, if at all? I assume the proposals could be grouped together in the same eval?

At the end of the day I'm wondering if it might not be simpler to have core proposals expressed as an array of grouped proposals, and not try to do any automatic resolution.

packages/deploy-script-support/src/extract-proposal.js Outdated Show resolved Hide resolved
packages/deploy-script-support/src/extract-proposal.js Outdated Show resolved Hide resolved
packages/deploy-script-support/src/extract-proposal.js Outdated Show resolved Hide resolved
packages/deploy-script-support/src/extract-proposal.js Outdated Show resolved Hide resolved
Comment on lines -264 to +312
code: defangAndTrim(code),
codeSteps,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit: this looks like a breaking change, which is only addressed in follow-up commits. My preference is usually to have all commits working. In this case I think it could have been done by switching to an array of steps first (aka the next commit), but containing only the current comingled proposals, then do the step extraction in this commit.

It does also raise the question if the extract proposal logic should actually support providing both?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this nit still applies, relayering by switching to handling codeSteps first would IMO be preferable, but I understand it'd be a decent amount of work for no good reason.

That said, extract proposal should definitely not provide both forms, that comment was misguided.

packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
@michaelfig
Copy link
Member Author

Potential for deadlock if core proposals have .needs that don't actually provide the functionality needed by the dependent to make progress.

This seems formulated backward. Did you mean that a dependent forgot to include some entry in its .needs, or did I misunderstand?

I meant: if there's a declaration that "b needs a", but "a" doesn't actually do the work that "b" needs in order to progress, then that will deadlock things that legitimately need "b".

  • Since we're going from an array to an object for the definitions, in what order are individual core evals executed if the proposals have no needs?

In parallel, as is the status quo. After this PR, every core proposal in a given step is grouped together for parallel evaluation.

  • How are cyclical needs resolved, if at all?

Cycles cause the solver to throw instead of returning any steps.

I assume the proposals could be grouped together in the same eval?

Yes, just as they are today. If their needs are satisfied, they will run opportunistically in parallel with all such other proposals that were satisfied in the prior step.

At the end of the day I'm wondering if it might not be simpler to have core proposals expressed as an array of grouped proposals, and not try to do any automatic resolution.

Yes, that was one of my earlier suggestions. If we did this, I'd introduce a different property to distinguish the grouping-of-parallel (say, coreProposalSteps: CoreProposal[][]), rather than coreProposals parallel-only, or this PR's automatic-grouping-of-parallel. I was unwilling to break the other tooling around coreProposals, but that may be acceptable.

@mhofman
Copy link
Member

mhofman commented Sep 26, 2023

At the end of the day I'm wondering if it might not be simpler to have core proposals expressed as an array of grouped proposals, and not try to do any automatic resolution.

Yes, that was one of my earlier suggestions. If we did this, I'd introduce a different property to distinguish the grouping-of-parallel (say, coreProposalSteps: CoreProposal[][]), rather than coreProposals parallel-only, or this PR's automatic-grouping-of-parallel. I was unwilling to break the other tooling around coreProposals, but that may be acceptable.

I'm not sure I follow. I think what I'm suggesting is to only change the template.json to be structured like:

type ProposalTemplate = Array<Record<string, { module: string, entrypoint?: string, args?: Array<unknown> }>>

With each template record resulting in a single core eval sequentially executed. The keys of the record would not have any actual use besides making it more explicit that each proposal entry in the record is parallel and not sequential.

I don't think we need to distinguish the only-parallel vs sequential-of-parallel because the former can be expressed as a single sequential step in the latter form, the same way the current PR only supports a single form.

@michaelfig michaelfig force-pushed the mfig-core-proposal-deps branch 2 times, most recently from 23a0822 to 3ff691e Compare December 7, 2023 01:24
@michaelfig michaelfig changed the title feat(extract-proposal): named proposals with expressed needs feat(extract-proposal): organize proposals into steps Dec 19, 2023
@michaelfig michaelfig force-pushed the mfig-core-proposal-deps branch 3 times, most recently from ae78e8d to 6730b31 Compare December 24, 2023 23:31
@mhofman mhofman self-requested a review December 29, 2023 21:14
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for simplifications in the extract logic from what I remember the last iteration was.

At this point I have 2 small concerns:

  • Nit: I wish we didn't keep 2 paths for how core proposals may be executed at bootstrap.
  • Because we don't yet have Report bridge inbound result to cosmic-swingset #8441, there is a risk that a core proposal step executed in bootstrap would behave differently than a core proposal step through the bridge for buggy core proposals that require future external input. The former would deadlock, highlighting the bug, whereas the latter would return to the host, and finish once that input arrives.

I need to think a little more about that last bit in the context of upgrades.

packages/cosmic-swingset/src/launch-chain.js Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
packages/vats/src/core/boot-solo.js Outdated Show resolved Hide resolved
packages/vats/src/core/lib-boot.js Show resolved Hide resolved
packages/deploy-script-support/src/extract-proposal.js Outdated Show resolved Hide resolved
Comment on lines -264 to +312
code: defangAndTrim(code),
codeSteps,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this nit still applies, relayering by switching to handling codeSteps first would IMO be preferable, but I understand it'd be a decent amount of work for no good reason.

That said, extract proposal should definitely not provide both forms, that comment was misguided.

@mhofman
Copy link
Member

mhofman commented Jan 2, 2024

I need to think a little more about that last bit in the context of upgrades.

@michaelfig reminds me that the difference goes in the other direction as well. An await of a step does not guarantee that the async side-effects of the step have gotten quiescent. Arguably that's also a bug of the steps themselves, as any errors would end up as some unhandled rejection somewhere, however that's a much harder one to detect. A series of core eval bridge messages would at least ensure these side effects would not overlap other proposal steps.

@michaelfig
Copy link
Member Author

  • Nit: I wish we didn't keep 2 paths for how core proposals may be executed at bootstrap.

So did I, until I discovered that eliminating the bootstrap vat path completely broke ag-solo.

there is a risk that a core proposal step executed in bootstrap would behave differently than a core proposal step through the bridge for buggy core proposals that require future external input. The former would deadlock, highlighting the bug, whereas the latter would return to the host, and finish once that input arrives.

That's one reason why I would recommend people test their core proposals by adding them to the chain config.json, which also happens to be the most expedient way to iterate on their deelopment until they work well enough to justify testing the cosgov way to propose and vote them in.

Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm conditionally approving given the following:

  • A comment is added to clarify in which case a coreProposal is executed directly as part of the bootstrap.
  • Consider an assertion we don't have both a coreProposal from bootstrap config, and upgradePlan, at least until we decide how that situation should be resolved. Right now ignoring coreProposals from the bootstrap config seems wrong.

@michaelfig
Copy link
Member Author

I'm conditionally approving given the following:

  • A comment is added to clarify in which case a coreProposal is executed directly as part of the bootstrap.

👍

  • Consider an assertion we don't have both a coreProposal from bootstrap config, and upgradePlan, at least until we decide how that situation should be resolved. Right now ignoring coreProposals from the bootstrap config seems wrong.

Let's follow up in: #8370 (comment)

@mhofman mhofman self-requested a review January 16, 2024 01:18
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core logic seems sane, just a couple nits.

However it does feel like we're bending backwards to recreate ENACTED_UPGRADE synthetic blocking sends, which golang no longer generates by itself anyway. @gibson042 and I were talking about possibly simplifying the logic there, which I suspect would allow us to remove some cruft here too.

packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
packages/cosmic-swingset/src/launch-chain.js Outdated Show resolved Hide resolved
@mhofman
Copy link
Member

mhofman commented Jan 17, 2024

Also please manually rebase before merging (I know the linear history test should check, but I have seen it let things through)

@mhofman mhofman self-requested a review January 17, 2024 14:23
@mhofman
Copy link
Member

mhofman commented Jan 17, 2024

After discussing, we'll get rid of ENACTED_UPGRADE, and I'll re-review

Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While functionally correct, I think we can move a few things around to make things more legible. Approving, but please consider the suggested fixes.

Comment on lines 802 to 804
// Merge the core proposals from the bootstrap block with the
// ones from the upgrade plan.
return mergeCoreProposals(bootstrapCoreProposals, coreProposals);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to do the merge inside doCosmosInit instead of the caller?

@@ -777,6 +778,99 @@ export async function launch({
});
}

const doCosmosInit = async (action, coreProposals) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be named doBootstrap.

Cosmos init is currently overloaded to mean every start of the software.

Comment on lines 903 to 905
// Start a block transaction, but without changing state
// for the upcoming begin block check
saveBeginHeight(savedBeginHeight);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this inside the doCoreProposals.

Comment on lines 899 to 900
if (!coreProposals || !blockNeedsExecution(blockHeight)) {
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While correct, this condition is confusing me. Can we restore the original, and instead do the following below?

        if (coreProposals) {
          await doCoreProposals(action, coreProposals);
        }
        return true;

} finally {
controller.writeSlogObject({
type: 'cosmic-swingset-bootstrap-block-finish',
blockTime: action.blockTime,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the already plucked blockTime above?

@michaelfig michaelfig added the automerge:no-update (expert!) Automatically merge without updates label Jan 23, 2024
return true;
}

case ActionType.ENACTED_UPGRADE: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh also, can we remove this ActionType export altogether?

@mergify mergify bot merged commit 09e90ee into master Jan 23, 2024
66 checks passed
@mergify mergify bot deleted the mfig-core-proposal-deps branch January 23, 2024 22:28
mhofman pushed a commit that referenced this pull request Jan 30, 2024
feat(extract-proposal): organize proposals into steps
mhofman pushed a commit that referenced this pull request Jan 30, 2024
feat(extract-proposal): organize proposals into steps
mhofman pushed a commit that referenced this pull request Jan 30, 2024
feat(extract-proposal): organize proposals into steps
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:no-update (expert!) Automatically merge without updates cosmic-swingset package: cosmic-swingset
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants