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

Registrar 3188 #3299

Merged
merged 7 commits into from
Jun 23, 2021
Merged

Registrar 3188 #3299

merged 7 commits into from
Jun 23, 2021

Conversation

Chris-Hibbert
Copy link
Contributor

@Chris-Hibbert Chris-Hibbert commented Jun 11, 2021

Add CommitteeRegistrar and test in a swingSet tests to show vats and invitations working.

closes #3188

Copy link
Contributor

@katelynsills katelynsills left a comment

Choose a reason for hiding this comment

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

I think I need more information about why certain choices were made:

  1. Why is checking for a quorum an async call?
  2. What does verifying a ballot mean, and when does a user do that? How easy is it for them?
  3. How is the notifier used? What use it is it to know the latest question?
  4. Why hand out invitations if there is no use of Zoe's escrow? What is the model of trust? Do the users trust this contract? Do users need to convince other users that this contract is legitimate?

methodP,
qNameP,
]);
log(`Verify ballot from instance: ${qName}, ${position}, ${method}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

How is this verifying the ballot? does the voter have to request all of this information and compare each? That doesn't seem right. Why not have a WeakSet that contains all of the properly made ballots and validate by sending the ballot in to be checked against the WeakSet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will want better support for usability. At this point, I'm trying to demonstrate that a voter can get a ballot and tell that it's connected to a particular BallotCounter and Registrar.

If you'd rather wait until everything is connected, I can stop sending PRs until all the pieces have been written.

};
E(clock).setWakeup(deadline, Far('waker', { wake }));

updater.updateState(questionDetails.question);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this updater? As written, the state it publishes is the latest question. What would be a scenario in which this is used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The voters use this updater to find out when new questions are added. If there are automated voters, they'll need something like this.

If they don't always respond immediately to each, they might use this as a prompt to check on older ones as well, so it will probably be helpful to make it possible to ask for all open questions (and maybe closed questions as well.) I haven't added that yet.

}

// This could be parameterized. For now, we check that at least half voted.
const quorumChecker = Far('checker', {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not have this be a parameter of the ballot counter, rather than an object whose methods must be called asynchronously?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right that it should be a legible parameter of the ballot counter, and I've made that change.

For the moment (with only binary ballots), it can be synchronous, but eventually, I expect to want the quorum checking to be pluggable, which means it has to be external to the contract, and hence asynchronous.

I've converted binaryBallots to use a static specification of the quorum threshold, but I expect to refactor this later.

const handler = voterSeat => {
return Far(`voter${index}`, {
castBallot: ballot =>
E(allQuestions.get(ballot.question)).submitVote(voterSeat, ballot),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we giving out invitations if nothing is escrowed, and this is just a way to submit votes? Why not give out a useFacet with the submitVote method on it? What is the model of who trusts who?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, we do not want to encourage users to sell or otherwise pass on their invitation, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use invitations so the recipient has some assurance of what they've received. The invitation allows them to verify which contract instance it came from, and look at the terms, which shows connections to other contract instances.

I don't see any reason to discourage people from passing invitations on. In democratic elections among people subject to a government it makes sense to insist that each ballot be cast by a unique person, but that's not important when the party receiving the ballot might be representing other interests.

And as MarkM sometimes says, it's a mistake to try to forbid what we can't prevent.

return Far('voter', {
createVoter: async (name, voteFacet) => {
return Far(`Voter ${name}`, {
voteBallot: (qName, ballot) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

If the voters are just casting ballots, why use invitations?

Copy link
Contributor

Choose a reason for hiding this comment

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

The qName parameter is not used

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR doesn't include an election manager, which will add some of the crucial connections to support validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added more legibility and more verification. I wouldn't claim it's done. Some of the legibility comes from the connections to the election manager.

const details2 = await E(zoe).getInvitationDetails(invitations[2]);

log(
`invitaiton details check: ${details2.instance === registrarInstance} ${
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
`invitaiton details check: ${details2.instance === registrarInstance} ${
`invitation details check: ${details2.instance === registrarInstance} ${

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

log(
`invitaiton details check: ${details2.instance === registrarInstance} ${
details2.description
}}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
}}`,
}`,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

const expectedCommitteeBinaryStartLog = [
'=> voter and registrar vats are set up',
'@@ schedule task for:3, currently: 0 @@',
'invitaiton details check: true Voter2}',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'invitaiton details check: true Voter2}',
'invitation details check: true Voter2',

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@katelynsills katelynsills removed this from the Testnet: Stress Test Phase milestone Jun 18, 2021
@Chris-Hibbert Chris-Hibbert force-pushed the buildBallot-3188 branch 3 times, most recently from ee7c381 to e943891 Compare June 18, 2021 22:54
@Chris-Hibbert
Copy link
Contributor Author

I think I need more information about why certain choices were made:
Why is checking for a quorum an async call?

In the binary ballot case, checking quorums is simple enough that we can parameterize it. I've done that for now. I think after we build the more general case, binaryBallots will want to be compatible.

In the general case, we might want to check for a majority of stakeholders at the end of the voting period, so it the quorum checker might need to check with an Oracle. But we can leave this out for now.

I tried to answer your questions here.

What does verifying a ballot mean, and when does a user do that? How easy is it for them?

The first version of all this will make it possible to verify. Making it easier will be a progressive project.

How is the notifier used? What use it is it to know the latest question?

The point isn't that they want to know the most recent one, it's that they want to know when there is a new one. It should be possible for them to get a complete list of open questions (and closed questions as well). I didn't build those first.

Why hand out invitations if there is no use of Zoe's escrow? What is the model of trust? Do the users trust this contract? Do users need to convince other users that this contract is legitimate?

Invitations are the only means we have of assuring someone that they're talking to a particular private interface. I haven't thought of a reason why one person would want to convince someone else, but someone using a contract might want to understand its governance structure even if they aren't a voter.

The code that goes in vats (Registrar, BallotCounter, ElectionManager) is that way so that users and others can verify what code is running. When people get access to private facets, it has to be via an invitation so they can tell what they're getting.

@Chris-Hibbert Chris-Hibbert force-pushed the buildBallot-3188 branch 3 times, most recently from c297a97 to b2c0331 Compare June 20, 2021 17:40
Base automatically changed from buildBallot-3188 to master June 20, 2021 21:33
@Chris-Hibbert Chris-Hibbert changed the base branch from master to closureRule June 21, 2021 16:31
Base automatically changed from closureRule to master June 21, 2021 22:14
@Chris-Hibbert Chris-Hibbert force-pushed the registrar-3188 branch 2 times, most recently from cd8f597 to a8bb7fb Compare June 21, 2021 23:19
Chris-Hibbert added a commit that referenced this pull request Jun 22, 2021
I want the Treasury changes to be on top of the registrar (#3299)
which is still in review. Git/GitHub doesn't allow an empty PR to be
rebased onto anther PR, so this adds a commit..
Copy link
Contributor

@katelynsills katelynsills left a comment

Choose a reason for hiding this comment

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

Looks good. Just tiny fixes. One design question related to seemingly excessive asynchronous calls in order to vote.

If I understand correctly, one invitation allows you to vote on all further questions. Can we have a test that exercises voting on more than one question. I'd like to see the user flow.

yarn.lock Outdated
@@ -11246,6 +11246,11 @@ [email protected]:
parseurl "~1.3.3"
send "0.17.1"

ses@^0.13.1:
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like we are specifying an old version of SES. Let's remove that entry in governance's package.json

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -31,19 +31,25 @@
"homepage": "https://github.com/Agoric/agoric-sdk#readme",
"dependencies": {
"@agoric/assert": "^0.3.0",
"@agoric/bundle-source": "^1.3.9",
Copy link
Contributor

Choose a reason for hiding this comment

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

This is only used in tests, right? So it's a devDependency

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

"@agoric/store": "^0.4.15",
"@agoric/swingset-vat": "^0.18.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

Same with this. It's only used in tests, so should be a devDependency

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

"ava": "^3.12.1",
"esm": "agoric-labs/esm#Agoric-built"
"esm": "agoric-labs/esm#Agoric-built",
"ses": "^0.13.1"
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be "ses": "^0.13.2"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I bumped it to 0.13.2 even though webstorm tells me that the most recent is 0.13.4. Is there a reason to stick to that older one?

];

test.serial('zoe - committee binary vote - valid inputs', async t => {
// test.serial('zoe - committee binary vote - valid inputs', async t => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup.

'Verify ballot from instance: Choose, Eeny,Meeny, choose_n',
'Emma cast a ballot on Choose for Meeny',
'Verify: q: Choose, max: 1, committee: TheCommittee',
'Verify: registrar: [Alleged: InstanceHandle], counter: [Alleged: InstanceHandle]',
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, can we log something that is more informative, such as comparing the instanceHandles to known ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure. My intent was to demonstrate that the instances were available to be verified, but I can send in the known instances for checking.

const counterRoot = `${__dirname}/../../src/binaryBallotCounter`;

async function setupContract() {
const zoe = makeZoe(makeFakeVatAdmin(() => {}).admin);
Copy link
Contributor

Choose a reason for hiding this comment

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

This can just be fakeVatAdmin (imported from fakeVatAdmin directly) if you're not passing a function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks. Done

zoe.install(registrarBundle),
zoe.install(counterBundle),
]);
const terms = { committeeName: 'illuminati', committeeSize: 13 };
Copy link
Contributor

Choose a reason for hiding this comment

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

crying

details3,
);
// We didn't add any votes
E(counterPublic)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think await t.throwsAsync() is the recommended way to test for a thrown error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is. But it doesn't work here.

I may be confused, but what I think is happening here is tick() causes the problem, but it doesn't happen before tick() returns, so I can't put throwsAsync() around the tick(). It also doesn't work to put the throwsAsync() around getOutcome(), since the problem doesn't happen until after tick(). So what I'm doing here is putting a catch clause on getOutcome() that will handle the rejected promise that will arise later.

I added a comment repeating this description.

...questionDetailsShort,
registrar: zcf.getInstance(),
};
// facets of the ballot counter. Suppress creatorInvitation and adminFaceet.
Copy link
Contributor

Choose a reason for hiding this comment

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

adminFacet

Copy link
Contributor

Choose a reason for hiding this comment

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

What does "suppress" mean here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not returning them to the caller of addQuestion(). If they need to be held, they should be held somewhere else, I think.

@Chris-Hibbert
Copy link
Contributor Author

If I understand correctly, one invitation allows you to vote on all further questions. Can we have a test that exercises voting on more than one question. I'd like to see the user flow.

Missed this earlier. I'll add a test now.

update testing imports for issue 768
add minimal types
better fix for test dependencies
change jsconfig.json includes, update packages, change swingset test (#3300)
update committeeRegistrar for relocation of voterFacet
integrate with changes to ballot PR (3233)
make ballotCounter instance accessible from ballot
add more to terms of ballotCounter (closureRule)
add more to public facet of Registrar
one registrar per contract/vat: details in terms
use zcf.getInstance() to supply instances

In tests
  voters look up their own positions
  voters cast ballots on notification
move some dependencies to devDependencies
expect promises for ballots
allow voters to cast directly with registrar
add a test for multiple votes by a single electorate
@Chris-Hibbert Chris-Hibbert merged commit 7547357 into master Jun 23, 2021
@Chris-Hibbert Chris-Hibbert deleted the registrar-3188 branch June 23, 2021 17:35
Chris-Hibbert added a commit that referenced this pull request Jul 7, 2021
I want the Treasury changes to be on top of the registrar (#3299)
which is still in review. Git/GitHub doesn't allow an empty PR to be
rebased onto anther PR, so this adds a commit..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Governance Governance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Committee Binary Vote (Governance)
3 participants