-
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
refactor: method schemas in Governance contracts #6114
Conversation
a99346b
to
bcc4bd9
Compare
export const NoParamChangesPositionShape = harden({ | ||
noChange: M.arrayOf(M.string()), | ||
}); | ||
export const ParamChangesPositionsShape = [ |
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.
export const ParamChangesPositionsShape = [ | |
export const ParamChangesPositionsShape = harden([ |
and several other places
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.
done
'offer_filter', | ||
); | ||
|
||
export const TimerShape = M.handle('timer'); |
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.
For a remotable, the most that the pattern system can enforce is that it is a remotable. The string argument is only for diagnostic purposes. So the following does all the enforcement you have in mind, but by itself fails to provide the diagnostic info that you're expecting a handle.
export const TimerShape = M.handle('timer'); | |
export const TimerShape = M.remotable('timer'); |
you could just indicate that in the name manually
export const TimerShape = M.handle('timer'); | |
export const TimerShape = M.remotable('timerHandle'); |
or, if you think it's worth it, create an abstraction that just does the name mangling
export const TimerShape = M.handle('timer'); | |
const makeHandleShape = name => M.remotable(`${name}Handle`); | |
//... | |
export const TimerShape = makeHandleShape('timer'); |
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.
cool! thanks.
54815db
to
3c0bcd7
Compare
ea40db9
to
0e12651
Compare
f0d2aa5
to
a2cff79
Compare
60a1188
to
711dd62
Compare
711dd62
to
6612417
Compare
6612417
to
50f9ee4
Compare
50f9ee4
to
70dd248
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.
Review going well but not done yet.
@@ -27,7 +28,7 @@ const validateQuestionDetails = async (zoe, electorate, details) => { | |||
counterInstance, | |||
issue: { contract: governedInstance }, | |||
} = details; | |||
validateParamChangeQuestion(details); | |||
fit(details, ParamChangesQuestionDetailsShape); |
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.
;)
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.
LGTM!
packages/governance/src/committee.js
Outdated
}); | ||
|
||
return { publicFacet, creatorFacet }; | ||
return makeCommitteeKit(); |
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.
Another one where the kit is instantiated only once, so the objects in the kit are singletons. You should just use makeHeapFarInstance
on each.
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.
done
packages/governance/src/committee.js
Outdated
getPoserInvitation() { | ||
return getPoserInvitation(zcf, async (voteCounter, questionSpec) => { | ||
const quorumThreshold = quorumRule => { |
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.
AFAICT, the body of the argument function here is identical to the body of the addQuestion
method below. Although the switch to inline concise methods admittedly make sharing this function harder, remember that you can send messages to self.
getPoserInvitation() { | |
return getPoserInvitation(zcf, async (voteCounter, questionSpec) => { | |
const quorumThreshold = quorumRule => { | |
getPoserInvitation() { | |
const { facet: { creatorFacet } } = this; | |
return getPoserInvitation(zcf, async (voteCounter, questionSpec) => | |
creatorFacet.addQuestion(voteCounter, questionSpec), | |
); | |
}, |
The suggestion above is if you stick with the defineHeapFarClassKit
. If you switch to multiple makeHeapFarInstance
s and call the lexical variable creatorFacet
, then the thisful line disappears and the rest of the suggestion still applies.
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.
Thank you. I should have noticed the duplication and looked for an appropriate way to get the sharing back.
// XXX It would be nice to enforce this using parameterized types, but that | ||
// seems to only enforce type constraints, (i.e. the tieOutcome will be the | ||
// same type as any of the positions) unless you can provide the concrete | ||
// value at pattern creation time. |
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.
yes. No change suggested.
@@ -43,124 +38,9 @@ const QuorumRule = /** @type {const} */ ({ | |||
ALL: 'all', | |||
}); | |||
|
|||
/** |
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.
Re the deletions from here (line 46) through line 196:
OMG that's a lot of manual input validation code deleted! Awesome!
It strikes me that this might serve as one of the extremes for our benchmarking, comparing manual input validation to pattern-based. Attn @gibson042 @warner
export const SimpleQuestionDetailsShape = harden({ | ||
method: ChoiceMethodShape, | ||
issue: SimpleIssueShape, | ||
positions: SimplePositionsShape, | ||
electionType: M.or('election', 'survey'), | ||
maxChoices: M.gte(1), | ||
closingRule: ClosingRuleShape, | ||
quorumRule: QuorumRuleShape, | ||
tieOutcome: NoSimplePositionShape, | ||
questionHandle: makeHandleShape('Question'), | ||
counterInstance: InstanceHandleShape, | ||
}); |
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.
AFAICT, the parts in common with SimpleQuestionSpecShape
are identical. If this is an intentional part of the design, then
export const SimpleQuestionDetailsShape = harden({ | |
method: ChoiceMethodShape, | |
issue: SimpleIssueShape, | |
positions: SimplePositionsShape, | |
electionType: M.or('election', 'survey'), | |
maxChoices: M.gte(1), | |
closingRule: ClosingRuleShape, | |
quorumRule: QuorumRuleShape, | |
tieOutcome: NoSimplePositionShape, | |
questionHandle: makeHandleShape('Question'), | |
counterInstance: InstanceHandleShape, | |
}); | |
export const SimpleQuestionDetailsShape = harden({ | |
...SimpleQuestionSpecShape, | |
questionHandle: makeHandleShape('Question'), | |
counterInstance: InstanceHandleShape, | |
}); |
Wherever interface extension is an intentional design, this is a good way to express it.
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. I was looking for that, and didn't find it.
// XXX I want to add questionHandle and counterInstance to | ||
// ParamChangesQuestionSpecShape. I don't see any alternative to adding the | ||
// methods to each member separately | ||
export const QuestionDetailsShape = M.or( | ||
ParamChangesQuestionDetailsShape, | ||
ApiInvocationQuestionDetailsShape, | ||
OfferFilterQuestionDetailsShape, | ||
SimpleQuestionDetailsShape, | ||
); |
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 putting the question inline. Would be good for anything in common to be pulled out of the expensive M.or
. If you pull these two common fields out of the branches, then you should also rename the branches to not imply that they're meaningful by themselves, and stop exporting them. For three of these, they are only used here, so no problem. But ParamChangesQuestionDetailsShape
is used elsewhere. Assuming that this is dealt with somehow, we could rewrite the factored pattern as
// XXX I want to add questionHandle and counterInstance to | |
// ParamChangesQuestionSpecShape. I don't see any alternative to adding the | |
// methods to each member separately | |
export const QuestionDetailsShape = M.or( | |
ParamChangesQuestionDetailsShape, | |
ApiInvocationQuestionDetailsShape, | |
OfferFilterQuestionDetailsShape, | |
SimpleQuestionDetailsShape, | |
); | |
export const QuestionDetailsShape = M.split({ | |
questionHandle: QuestionHandleShape, // making the handle shape should already be factored out. | |
counterInstance: InstanceHandleShape, | |
}, | |
M.or( | |
ParamChangesQuestionPartialDetailsShape, | |
ApiInvocationQuestionPartialDetailsShape, | |
OfferFilterQuestionPartialDetailsShape, | |
SimpleQuestionPartialDetailsShape, | |
), | |
}); |
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 the explanation. That's a helpful alternative.
Now that I see how ParamChangesQuestionDetailsShape
is used, I wouldn't be surprised to find other uses of the other QuestionDetailsShape
s. I think I'll leave it as is.
split interfaces in BinaryVoteCounter to separate heapFarInstances include unused parameters in interface methods move some guards to Zoe harden some arrays `1` is better than `M.eq(1)`
split up more makeHeapFarInstances clean up some interface shapes. reduce duplication between farInstance methods
8aaeb3d
to
6bd1cc4
Compare
closes: #6060
Description
Convert Governance contracts to use method schemas
Can be reviewed as separate commits:
commit 0: basic governance types
commit 1: committee as heapFarClass
commit 2: binaryVoteCounter and questionDetails as heapFarClasses
Security Considerations
This uses method schemas to enforce types in the APIs.
Documentation Considerations
No changes in behavior.
Testing Considerations
Existing tests pass. I didn't add tests for out-of-range parameters.