UNPKG

pulsar-contracts

Version:

227 lines 8.84 kB
import { Mina, PrivateKey, AccountUpdate, Poseidon, fetchAccount, Lightnet, UInt64, } from 'o1js'; import { MultisigVerifierProgram, } from '../SettlementProof.js'; import { AGGREGATE_THRESHOLD, ENDPOINTS, VALIDATOR_NUMBER, } from '../utils/constants.js'; import { SettlementContract } from '../SettlementContract.js'; import { devnetTestAccounts, validatorSet, testAccounts } from './mock.js'; import { TestUtils } from '../utils/testUtils.js'; import { ValidateReduceProgram } from '../ValidateReduce.js'; import { List } from '../types/common.js'; import { ActionStackProgram } from '../ActionStack.js'; import { MapFromArray, PrepareBatch } from '../utils/reduceWitness.js'; import { analyzeMethods, enableLogs, log } from '../utils/loggers.js'; const testEnvironment = process.env.TEST_ENV ?? 'local'; const localTest = testEnvironment === 'local'; const randomKeys = process.env.RANDOM_KEYS === '1'; let fee = localTest ? 0 : 1e9; const proofsEnabled = process.env.PROOFS_ENABLED === '1'; let MINA_NODE_ENDPOINT; let MINA_ARCHIVE_ENDPOINT; let MINA_EXPLORER; let testAccountIndex = 10; if (testEnvironment === 'devnet') { MINA_NODE_ENDPOINT = ENDPOINTS.NODE.devnet; MINA_ARCHIVE_ENDPOINT = ENDPOINTS.ARCHIVE.devnet; MINA_EXPLORER = ENDPOINTS.EXPLORER.devnet; } else { MINA_NODE_ENDPOINT = ENDPOINTS.NODE.lightnet; MINA_ARCHIVE_ENDPOINT = ENDPOINTS.ARCHIVE.lightnet; MINA_EXPLORER = ENDPOINTS.EXPLORER.lightnet; } //keys let feePayerKey; let usersKeys = []; //public keys // let feePayerAccount: PublicKey; let usersAccounts = []; //validator variables let merkleList; let activeSet = []; // proofs let settlementProof; // action stack let actionStack = []; // ZkApp let zkappAddress; let zkappPrivateKey; let zkapp; // Local Mina blockchain let Local; merkleList = List.empty(); activeSet = validatorSet.slice(0, VALIDATOR_NUMBER); for (let i = 0; i < VALIDATOR_NUMBER; i++) { const [, publicKey] = activeSet[i]; merkleList.push(Poseidon.hash(publicKey.toFields())); } if (testEnvironment === 'local') { Local = await Mina.LocalBlockchain({ proofsEnabled }); Mina.setActiveInstance(Local); feePayerKey = Local.testAccounts[0].key; // feePayerAccount = feePayerKey.toPublicKey(); for (let i = 0; i < 5; i++) { let { key } = Local.testAccounts[i + 1]; if (!randomKeys) { await sendMina(key, testAccounts[testAccountIndex][1], UInt64.from(1e11)); key = testAccounts[testAccountIndex][0]; testAccountIndex++; } usersKeys.push(key); usersAccounts.push(key.toPublicKey()); } } else if (testEnvironment === 'devnet') { // Set up the Mina devnet const Network = Mina.Network({ mina: MINA_NODE_ENDPOINT, archive: MINA_ARCHIVE_ENDPOINT, }); Mina.setActiveInstance(Network); feePayerKey = devnetTestAccounts[0][0]; // feePayerAccount = devnetTestAccounts[0][1]; for (let i = 1; i < 5; i++) { let [key] = devnetTestAccounts[i]; if (!randomKeys) { await sendMina(key, testAccounts[testAccountIndex][1], UInt64.from(1e11)); key = testAccounts[testAccountIndex][0]; testAccountIndex++; } usersKeys.push(key); usersAccounts.push(key.toPublicKey()); } } else { const Network = Mina.Network({ mina: MINA_NODE_ENDPOINT, archive: MINA_ARCHIVE_ENDPOINT, lightnetAccountManager: 'http://127.0.0.1:8181', }); Mina.setActiveInstance(Network); feePayerKey = (await Lightnet.acquireKeyPair()).privateKey; // feePayerAccount = feePayerKey.toPublicKey(); for (let i = 0; i < 5; i++) { let { privateKey: key } = await Lightnet.acquireKeyPair(); if (!randomKeys) { await sendMina(key, testAccounts[testAccountIndex][1], UInt64.from(1e11)); key = testAccounts[testAccountIndex][0]; testAccountIndex++; } usersKeys.push(key); usersAccounts.push(key.toPublicKey()); } } zkappPrivateKey = randomKeys ? PrivateKey.random() : testAccounts[testAccountIndex][0]; testAccountIndex++; zkappAddress = zkappPrivateKey.toPublicKey(); zkapp = new SettlementContract(zkappAddress); if (process.env.LOGS_ENABLED === '1') { enableLogs(); } const validateReduceAnalyze = await ValidateReduceProgram.analyzeMethods(); analyzeMethods(validateReduceAnalyze); const actionStackAnalyze = await ActionStackProgram.analyzeMethods(); analyzeMethods(actionStackAnalyze); const multisigVerifierAnalyze = await MultisigVerifierProgram.analyzeMethods(); analyzeMethods(multisigVerifierAnalyze); const settlementContractAnalyze = await SettlementContract.analyzeMethods(); analyzeMethods(settlementContractAnalyze); await MultisigVerifierProgram.compile({ proofsEnabled, }); log('MultisigVerifierProgram compiled'); await ValidateReduceProgram.compile({ proofsEnabled, }); log('ValidateReduceProgram compiled'); await ActionStackProgram.compile({ proofsEnabled, }); log('ActionStackProgram compiled'); if (proofsEnabled) { await SettlementContract.compile(); log('SettlementContract compiled'); } async function sendMina(senderKey, receiverKey, amount) { const tx = await Mina.transaction({ sender: senderKey.toPublicKey(), fee }, async () => { const senderAccount = AccountUpdate.createSigned(senderKey.toPublicKey()); AccountUpdate.fundNewAccount(senderKey.toPublicKey()); senderAccount.send({ to: receiverKey, amount }); }); await waitTransactionAndFetchAccount(tx, [senderKey], [receiverKey]); } async function waitTransactionAndFetchAccount(tx, keys, accountsToFetch) { try { // log('proving and sending transaction'); await tx.prove(); const pendingTransaction = await tx.sign(keys).send(); // log('waiting for transaction to be included in a block'); if (!localTest) { log(`${MINA_EXPLORER}${pendingTransaction.hash}`); const status = await pendingTransaction.safeWait(); if (status.status === 'rejected') { throw new Error('Transaction was rejected: ' + JSON.stringify(status.errors, null, 2)); } if (accountsToFetch) { await fetchAccounts(accountsToFetch); } } } catch (error) { log('error', error); throw error; } } async function fetchAccounts(accounts) { if (localTest) return; for (let account of accounts) { await fetchAccount({ publicKey: account }); } } async function deployAndInitializeContract(zkapp, deployerKey, zkappPrivateKey, merkleListRoot) { const deployerAccount = deployerKey.toPublicKey(); const tx = await Mina.transaction({ sender: deployerAccount, fee }, async () => { AccountUpdate.fundNewAccount(deployerAccount); await zkapp.deploy(); await zkapp.initialize(merkleListRoot); }); await waitTransactionAndFetchAccount(tx, [deployerKey, zkappPrivateKey], [zkapp.address, deployerAccount]); } async function prepareNewContract() { zkappPrivateKey = randomKeys ? PrivateKey.random() : testAccounts[testAccountIndex][0]; testAccountIndex++; zkappAddress = zkappPrivateKey.toPublicKey(); zkapp = new SettlementContract(zkappAddress); await deployAndInitializeContract(zkapp, feePayerKey, zkappPrivateKey, merkleList.hash); actionStack = []; } async function settle(senderKey, settlementProof, pushToStack = true) { await fetchAccounts([zkappAddress]); const tx = await Mina.transaction({ sender: senderKey.toPublicKey(), fee }, async () => { await zkapp.settle(settlementProof); }); if (pushToStack) { actionStack.push(settlementProof.publicInput.actionHash()); } log('settle tx', JSON.parse(tx.toJSON())); await waitTransactionAndFetchAccount(tx, [senderKey], [zkappAddress]); } async function reduce(senderKey) { let map = MapFromArray(actionStack); const { batch, useActionStack, actionStackProof, publicInput, mask } = await PrepareBatch(map, zkapp); const { validateReduceProof } = await TestUtils.MockReducerVerifierProof(publicInput, activeSet); log('mask', mask.toJSON()); const tx = await Mina.transaction({ sender: senderKey.toPublicKey(), fee }, async () => { await zkapp.reduce(batch, useActionStack, actionStackProof, mask, validateReduceProof); }); await waitTransactionAndFetchAccount(tx, [senderKey], [zkappAddress]); } await prepareNewContract(); log('ZkApp deployed and initialized:', zkappAddress.toBase58()); settlementProof = await TestUtils.GenerateTestSettlementProof(activeSet, 0, AGGREGATE_THRESHOLD); await settle(feePayerKey, settlementProof); await reduce(feePayerKey); //# sourceMappingURL=reduceScript.js.map