-
Notifications
You must be signed in to change notification settings - Fork 206
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
Conversation
12ce2e1
to
ff780ce
Compare
There was a problem hiding this 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.
code: defangAndTrim(code), | ||
codeSteps, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
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".
In parallel, as is the status quo. After this PR, every core proposal in a given step is grouped together for parallel evaluation.
Cycles cause the solver to throw instead of returning any steps.
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.
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, |
I'm not sure I follow. I think what I'm suggesting is to only change the 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. |
23a0822
to
3ff691e
Compare
ae78e8d
to
6730b31
Compare
There was a problem hiding this 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.
code: defangAndTrim(code), | ||
codeSteps, |
There was a problem hiding this comment.
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.
@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. |
So did I, until I discovered that eliminating the bootstrap vat path completely broke
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. |
There was a problem hiding this 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, andupgradePlan
, at least until we decide how that situation should be resolved. Right now ignoringcoreProposals
from the bootstrap config seems wrong.
👍
Let's follow up in: #8370 (comment) |
There was a problem hiding this 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.
Also please manually rebase before merging (I know the linear history test should check, but I have seen it let things through) |
After discussing, we'll get rid of |
There was a problem hiding this 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.
// Merge the core proposals from the bootstrap block with the | ||
// ones from the upgrade plan. | ||
return mergeCoreProposals(bootstrapCoreProposals, coreProposals); |
There was a problem hiding this comment.
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) => { |
There was a problem hiding this comment.
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.
// Start a block transaction, but without changing state | ||
// for the upcoming begin block check | ||
saveBeginHeight(savedBeginHeight); |
There was a problem hiding this comment.
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
.
if (!coreProposals || !blockNeedsExecution(blockHeight)) { | ||
return true; |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
374e1a4
to
2b38ebc
Compare
return true; | ||
} | ||
|
||
case ActionType.ENACTED_UPGRADE: { |
There was a problem hiding this comment.
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?
feat(extract-proposal): organize proposals into steps
feat(extract-proposal): organize proposals into steps
feat(extract-proposal): organize proposals into steps
refs: #8219
related: #8441
Description
Given
coreProposals: ParallelProposals | { steps: ParallelProposals[] }
(withtypedef ParallelProposals = Proposal[]
), returncodeSteps: string[]
fromextractCoreProposalBundles
. Then execute eachParallelProposals
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.