/
create-vote.js
80 lines (62 loc) · 3.38 KB
/
create-vote.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
const { getPublicAddress } = require('factom'),
{ generateEligibleVotersChain,
generateVoteChain,
generateVoteRegistrationEntry,
generateAppendEligibleVotersEntry } = require('./create-vote-struct'),
{ getVoteIdentity, extractKey, getPublicIdentityKey, getSecretIdentityKey } = require('../factom-identity');
async function createVote(cli, voteData, ecAddress) {
const { definition, registrationChainId, eligibleVoters, identity } = voteData;
if (!await cli.chainExists(registrationChainId)) {
throw new Error(`Registration chain ${registrationChainId} doesn't exist.`);
}
const initiator = await getVoteIdentity(cli, identity);
const defCopy = JSON.parse(JSON.stringify(definition));
const chainsToCreate = [];
if (!defCopy.vote.eligibleVotersChainId) {
const height = await cli.getHeights().then(heights => heights.leaderHeight);
if (defCopy.vote.phasesBlockHeights.commitStart <= height) {
throw new Error(`Current height (${height}) is higher than commitStart height (${defCopy.vote.phasesBlockHeights.commitStart}) making your new eligible voters list unusable.`);
}
const eligibleVotersChain = generateEligibleVotersChain(eligibleVoters || [], initiator);
defCopy.vote.eligibleVotersChainId = eligibleVotersChain.idHex;
chainsToCreate.push(eligibleVotersChain);
}
const voteChain = generateVoteChain(defCopy, initiator);
chainsToCreate.push(voteChain);
const registrationEntry = generateVoteRegistrationEntry(registrationChainId, voteChain.id);
const ecCost = registrationEntry.ecCost() + chainsToCreate.map(c => c.ecCost()).reduce((acc, cur) => acc + cur, 0);
await validateFunds(cli, ecCost, ecAddress, 'Cannot create vote');
const [voteChainAdded, eligibleVotersChainAdded] = await cli.add(chainsToCreate.reverse(), ecAddress);
const registration = await cli.add(registrationEntry, ecAddress);
return {
eligibleVoters: eligibleVotersChainAdded,
vote: voteChainAdded,
registration
};
}
async function appendEligibleVoters(cli, appendEligibleVotersData, ecAddress) {
const { eligibleVoters, eligibleVotersChainId, identityKey } = appendEligibleVotersData;
const canAppend = await canAppendEligibleVoters(cli, eligibleVotersChainId, identityKey);
if (!canAppend) {
throw new Error(`The initiator secret key is not authorized to add eligible voters to [${eligibleVotersChainId}].`);
}
const secretKey = extractKey(await getSecretIdentityKey(cli, identityKey));
const entry = generateAppendEligibleVotersEntry(eligibleVoters, eligibleVotersChainId, secretKey);
await validateFunds(cli, entry.ecCost(), ecAddress, 'Cannot append eligible voters');
return cli.add(entry, ecAddress);
}
async function validateFunds(cli, ecCost, ecAddress, message) {
const balance = await cli.getBalance(ecAddress);
if (ecCost > balance) {
throw new Error(`${message}. Not enough EC on ${getPublicAddress(ecAddress)}. Required: ${ecCost}EC. Available: ${balance}EC`);
}
}
async function canAppendEligibleVoters(cli, eligibleVotersChainId, identityKey) {
const firstEntry = await cli.getFirstEntry(eligibleVotersChainId);
const publicKey = extractKey(getPublicIdentityKey(identityKey));
return publicKey.equals(firstEntry.extIds[3]);
}
module.exports = {
createVote,
appendEligibleVoters
};