UNPKG

pulsar-contracts

Version:

180 lines 8.82 kB
import { Field, Poseidon, PrivateKey, Signature, UInt64, } from 'o1js'; import { BlockList, MultisigVerifierProgram, } from '../SettlementProof.js'; import { GenerateValidateReduceProof, GenerateSettlementPublicInput, MergeSettlementProofs, GeneratePulsarBlock, } from './generateFunctions.js'; import { ValidateReducePublicInput } from '../ValidateReduce.js'; import { SignaturePublicKeyList, SignaturePublicKeyMatrix, } from '../types/signaturePubKeyList.js'; import { List } from '../types/common.js'; import { PulsarAction } from '../types/PulsarAction.js'; import { ProofGenerators } from '../types/proofGenerators.js'; import { actionListAdd, emptyActionListHash, merkleActionsAdd, } from '../types/actionHelpers.js'; import { BATCH_SIZE, MAX_DEPOSIT_PER_BATCH, MAX_SETTLEMENT_PER_BATCH, MAX_WITHDRAWAL_PER_BATCH, SETTLEMENT_MATRIX_SIZE, } from './constants.js'; export const TestUtils = { GenerateSignaturePubKeyList, GenerateSignaturePubKeyMatrix, GenerateReducerSignatureList, GenerateTestSettlementProof, MockReducerVerifierProof, GenerateTestActions, CalculateActionRoot, GenerateTestBlocks, CreateValidatorMerkleList, CalculateFromMockActions, }; function GenerateSignaturePubKeyList(signatureMessage, signerSet) { const signatures = []; for (let i = 0; i < signerSet.length; i++) { signatures.push(Signature.create(signerSet[i][0], signatureMessage)); } return SignaturePublicKeyList.fromArray(signatures.map((signature, i) => [signature, signerSet[i][1]])); } function GenerateSignaturePubKeyMatrix(blocks, signerSet) { const signatureMatrix = []; for (let i = 0; i < SETTLEMENT_MATRIX_SIZE; i++) { signatureMatrix.push(GenerateSignaturePubKeyList(blocks[i].hash().toFields(), signerSet[i])); } return SignaturePublicKeyMatrix.fromArray(signatureMatrix.map((list) => list.list.map((item) => [item.signature, item.publicKey]))); } function GenerateReducerSignatureList(publicInput, proofGeneratorsList) { const signatures = []; const message = publicInput.hash().toFields(); for (let i = 0; i < proofGeneratorsList.length; i++) { signatures.push(Signature.create(proofGeneratorsList[i][0], message)); } return SignaturePublicKeyList.fromArray(signatures.map((signature, i) => [signature, proofGeneratorsList[i][1]])); } function CreateValidatorMerkleList(validatorSet) { const merkleList = List.empty(); for (let i = 0; i < validatorSet.length; i++) { const [, publicKey] = validatorSet[i]; merkleList.push(Poseidon.hash(publicKey.toFields())); } return merkleList; } async function GenerateTestSettlementProof(validatorSet, initialBlockHeight, newBlockHeight, initialStateRoot = initialBlockHeight, newStateRoot = newBlockHeight) { if (newBlockHeight - initialBlockHeight <= 0 || (newBlockHeight - initialBlockHeight) % SETTLEMENT_MATRIX_SIZE !== 0) { throw new Error(`newBlockHeight must be greater than initialBlockHeight and difference must be a multiple of ${SETTLEMENT_MATRIX_SIZE}`); } const settlementProofs = []; const merkleList = CreateValidatorMerkleList(validatorSet); let blocks = []; let index = 1; for (let i = initialBlockHeight; i < newBlockHeight; i++, index++) { const block = GeneratePulsarBlock(merkleList.hash, Field.from(i == initialBlockHeight ? initialStateRoot : blocks[i - initialBlockHeight - 1].NewStateRoot), Field.from(i), merkleList.hash, Field.from(i == newBlockHeight - 1 ? newStateRoot : Field.random()), Field.from(i + 1)); blocks.push(block); if (index % SETTLEMENT_MATRIX_SIZE === 0) { const publicInput = GenerateSettlementPublicInput(merkleList.hash, blocks[blocks.length - SETTLEMENT_MATRIX_SIZE].InitialStateRoot, blocks[blocks.length - SETTLEMENT_MATRIX_SIZE].InitialBlockHeight, blocks[blocks.length - 1].NewMerkleListRoot, blocks[blocks.length - 1].NewStateRoot, blocks[blocks.length - 1].NewBlockHeight, [validatorSet[0][1]]); const signatureMatrix = GenerateSignaturePubKeyMatrix(blocks.slice(-SETTLEMENT_MATRIX_SIZE), Array.from({ length: SETTLEMENT_MATRIX_SIZE }, () => validatorSet)); const proof = (await MultisigVerifierProgram.verifySignatures(publicInput, signatureMatrix, validatorSet[0][1], BlockList.fromArray(blocks.slice(-SETTLEMENT_MATRIX_SIZE)))).proof; settlementProofs.push(proof); } } let mergedProof = await MergeSettlementProofs(settlementProofs); return mergedProof; } async function MockReducerVerifierProof(publicInput, validatorSet) { const signatureList = GenerateReducerSignatureList(publicInput, validatorSet); return { validateReduceProof: await GenerateValidateReduceProof(publicInput, signatureList), }; } function GenerateTestActions(numActions, merkleListRoot, initialStateRoot = Field(0)) { const actions = []; let blockHeight = 1; for (let i = 0; i < numActions; i++) { const randomType = Math.ceil(Math.random() * 3); if (randomType === 1) { actions.push(PulsarAction.settlement(i == 0 ? initialStateRoot : Field.random(), Field.random(), merkleListRoot, merkleListRoot, Field.from(blockHeight++), Field.from(blockHeight++), ProofGenerators.empty().insertAt(Field.from(0), PrivateKey.random().toPublicKey()))); } else if (randomType === 2) { actions.push(PulsarAction.deposit(PrivateKey.random().toPublicKey(), UInt64.from(Math.floor(Math.random() * 2 ** 32)).value)); } else if (randomType === 3) { actions.push(PulsarAction.withdrawal(PrivateKey.random().toPublicKey(), UInt64.from(Math.floor(Math.random() * 2 ** 32)).value)); } } return actions; } function CalculateActionRoot(initialRoot, actions) { let actionRoot = initialRoot; for (const action of actions) { actionRoot = merkleActionsAdd(actionRoot, actionListAdd(emptyActionListHash, action)); } return actionRoot; } function GenerateTestBlocks(initialBlockHeight, initialMerkleListRoot, initialStateRoot = Field(0)) { const blocks = []; for (let i = 0; i < SETTLEMENT_MATRIX_SIZE; i++) { blocks.push(GeneratePulsarBlock(initialMerkleListRoot, initialStateRoot, initialBlockHeight, initialMerkleListRoot, initialStateRoot.add(Field(1)), initialBlockHeight.add(Field(1)))); initialBlockHeight = initialBlockHeight.add(Field(1)); initialStateRoot = initialStateRoot.add(Field(1)); } return blocks; } function CalculateFromMockActions(initialState, packedActions) { let withdrawals = 0; let deposits = 0; let settlements = 0; const batchActions = []; let endActionState = 0n; let publicInput = initialState; for (const [, pack] of packedActions.entries()) { if (batchActions.length === BATCH_SIZE) { break; } if (PulsarAction.isSettlement(pack.action).toBoolean()) { if (settlements === MAX_SETTLEMENT_PER_BATCH) { break; } settlements++; publicInput = new ValidateReducePublicInput({ ...publicInput, stateRoot: pack.action.newState, merkleListRoot: pack.action.newMerkleListRoot, blockHeight: pack.action.newBlockHeight, rewardListHash: Poseidon.hash([ publicInput.rewardListHash, pack.action.rewardListUpdateHash, ]), }); } else if (PulsarAction.isDeposit(pack.action).toBoolean()) { if (deposits === MAX_DEPOSIT_PER_BATCH) { break; } deposits++; publicInput = new ValidateReducePublicInput({ ...publicInput, depositListHash: Poseidon.hash([ publicInput.depositListHash, ...pack.action.account.toFields(), pack.action.amount, ]), }); } else if (PulsarAction.isWithdrawal(pack.action).toBoolean()) { if (withdrawals === MAX_WITHDRAWAL_PER_BATCH) { break; } withdrawals++; publicInput = new ValidateReducePublicInput({ ...publicInput, withdrawalListHash: Poseidon.hash([ publicInput.withdrawalListHash, ...pack.action.account.toFields(), pack.action.amount, ]), }); } batchActions.push(pack.action); endActionState = BigInt(pack.hash); } return { endActionState, batchActions, publicInput, }; } //# sourceMappingURL=testUtils.js.map