UNPKG

o1js

Version:

TypeScript framework for zk-SNARKs and zkApps

112 lines (103 loc) 3.46 kB
import { Member, MyMerkleWitness } from './member.js'; import { OffchainStorage } from './off-chain-storage.js'; import { Voting_ } from './voting.js'; import { Mina, PrivateKey } from 'o1js'; /** * Updates off-chain storage when registering a member or candidate * @param {bigint} i index of memberStore or candidatesStore * @param {Member} m member to register * @param {OffchainStorage<Member>} store off-chain store which should be used when registering a new member * @param {any} Local local blockchain instance in use */ export function registerMember( i: bigint, m: Member, store: OffchainStorage<Member>, Local: any ): Member { Local.addAccount(m.publicKey, m.balance.toString()); // we will also have to keep track of new voters and candidates within our off-chain merkle tree store.set(i, m); // setting voter 0n // setting the merkle witness m.witness = new MyMerkleWitness(store.getWitness(i)); return m; } /** * Updates off-chain storage after voting * @param {bigint} i index of candidateStore and votesStore * @param {OffchainStorage<Member>} votesStore votes off-chain storage * @param {OffchainStorage<Member>} votesStore candidates off-chain storage */ export function vote( i: bigint, votesStore: OffchainStorage<Member>, candidateStore: OffchainStorage<Member> ) { let c_ = votesStore.get(i)!; if (!c_) { votesStore.set(i, candidateStore.get(i)!); c_ = votesStore.get(i)!; } c_ = c_.addVote(); votesStore.set(i, c_); return c_; } /** * Prints the voting results of an election */ export function getResults( voting: Voting_, votesStore: OffchainStorage<Member> ) { if (!voting.committedVotes.get().equals(votesStore.getRoot()).toBoolean()) { throw new Error('On-chain root is not up to date with the off-chain tree'); } let result: Record<string, number> = {}; votesStore.forEach((m, i) => { result[m.publicKey.toBase58()] = Number(m.votes.toString()); }); return result; } /** * Checks if a transaction is valid. * If it is expected to fail, an expected error message needs to be provided * @boolean expectedToBeValid - true if the transaction is expected to pass without error */ export async function assertValidTx( expectToBeValid: boolean, cb: () => Promise<void>, signers: PrivateKey | [PrivateKey, ...PrivateKey[]], msg?: string ) { let failed = false; let err; if (!Array.isArray(signers)) signers = [signers]; let [feePayer] = signers; try { let tx = await Mina.transaction(feePayer.toPublicKey(), cb); await tx.prove(); await tx.sign(signers).send(); } catch (e: any) { failed = true; err = e; } if (!failed && expectToBeValid) { console.log('> transaction valid!'); } else if (failed && expectToBeValid) { console.error('transaction failed but should have passed'); console.log(cb.toString()); console.error('with error message: '); throw Error(err); } else if (failed && !expectToBeValid) { if (err.message.includes(msg ?? 'NO__EXPECTED_ERROR_MESSAGE_SET')) { console.log('> transaction failed, as expected!'); } else { console.log(err); throw Error('transaction failed, but got a different error message!'); } } else if (!failed && !expectToBeValid) { throw Error('transaction passed but should have failed'); } else { throw Error('transaction was expected to fail but it passed'); } }