UNPKG

@nori-zk/ethprocessor

Version:

zkApp for verifying SP1 Helios Nori proof and storing latest execution state root on Mina

128 lines 5.71 kB
import { AccountUpdate, Mina, PrivateKey, fetchAccount } from 'o1js'; import { Logger, NodeProofLeft } from '@nori-zk/proof-conversion'; import { EthProcessor } from './EthProcessor.js'; import { EthVerifier, EthInput } from './EthVerifier.js'; import { compileAndVerifyContracts, decodeConsensusMptProof } from './utils.js'; import { Bytes32FieldPair } from './types.js'; const logger = new Logger('EthProcessorSubmitter'); export class MinaEthProcessorSubmitter { constructor(type = 'plonk') { this.type = type; logger.info(`🛠 MinaEthProcessorSubmitter constructor called!`); const errors = []; const senderPrivateKeyBase58 = process.env.SENDER_PRIVATE_KEY; const network = process.env.NETWORK; const zkAppPrivateKeyBase58 = process.env.ZKAPP_PRIVATE_KEY; if (!senderPrivateKeyBase58) errors.push('SENDER_PRIVATE_KEY is required'); if (!network) { errors.push('NETWORK is required'); } else if (!['devnet', 'mainnet', 'lightnet'].includes(network)) { errors.push(`NETWORK must be one of: devnet, mainnet, lightnet (got "${network}")`); } else { this.network = network; } if (!zkAppPrivateKeyBase58) { errors.push('ZKAPP_PRIVATE_KEY is required when not in lightnet mode'); } if (errors.length > 0) { throw `Configuration errors:\n- ${errors.join('\n- ')}`; } this.senderPrivateKey = PrivateKey.fromBase58(senderPrivateKeyBase58); this.zkAppPrivateKey = PrivateKey.fromBase58(zkAppPrivateKeyBase58); this.zkApp = new EthProcessor(this.zkAppPrivateKey.toPublicKey()); this.txFee = Number(process.env.TX_FEE || 0.1) * 1e9; logger.log('Loaded constants from: .env'); } async networkSetUp() { logger.log('Setting up network.'); const networkUrl = process.env.MINA_RPC_NETWORK_URL || 'https://api.minascan.io/node/devnet/v1/graphql'; const networkId = this.network === 'mainnet' ? 'mainnet' : 'testnet'; const Network = Mina.Network({ networkId, mina: networkUrl, }); Mina.setActiveInstance(Network); logger.log('Finished Mina network setup.'); } async compileContracts() { const { ethVerifierVerificationKey, ethProcessorVerificationKey } = await compileAndVerifyContracts(logger); this.ethVerifierVerificationKey = ethVerifierVerificationKey; this.ethProcessorVerificationKey = ethProcessorVerificationKey; } async deployContract(storeHash) { logger.log('Creating deploy update transaction.'); const deployTx = await Mina.transaction({ sender: this.senderPrivateKey.toPublicKey(), fee: this.txFee }, async () => { AccountUpdate.fundNewAccount(this.senderPrivateKey.toPublicKey()); await this.zkApp.deploy({ verificationKey: this.ethProcessorVerificationKey, storeHash: Bytes32FieldPair.fromBytes32(storeHash), }); }); logger.log('Deploy transaction created successfully. Proving...'); await deployTx.prove(); logger.log('Transaction proved. Signing and sending the transaction...'); await deployTx .sign([this.senderPrivateKey, this.zkAppPrivateKey]) .send() .wait(); logger.log('EthProcessor deployed successfully.'); } async createProof(proofArguments) { try { logger.log('Creating proof.'); const { sp1PlonkProof, conversionOutputProof } = proofArguments; const rawProof = await NodeProofLeft.fromJSON(conversionOutputProof.proofData); const ethSP1Proof = sp1PlonkProof; logger.log('Decoding converted proof and creating verification inputs.'); // Decode proof values and create input for verification. const input = new EthInput(decodeConsensusMptProof(ethSP1Proof)); // Compute and verify proof. logger.log('Computing proof.'); return EthVerifier.compute(input, rawProof); } catch (err) { logger.error(`Error computing proof: ${String(err)}`); throw err; } } async submit(ethProof) { logger.log('Submitting a proof.'); try { await fetchAccount({ publicKey: this.zkApp.address }); await fetchAccount({ publicKey: this.senderPrivateKey.toPublicKey(), }); logger.log('Fetched accounts.'); logger.log('Creating update transaction.'); const updateTx = await Mina.transaction({ sender: this.senderPrivateKey.toPublicKey(), fee: this.txFee, memo: `State for slot ${ethProof.publicInput.outputSlot.toString()} set`, }, async () => { await this.zkApp.update(ethProof); }); await updateTx.prove(); logger.log('Transaction proven.'); const tx = await updateTx.sign([this.senderPrivateKey]).send(); logger.log(`Transaction sent to '${this.network}'.`); const txId = tx.data.sendZkapp.zkapp.id; const txHash = tx.data.sendZkapp.zkapp.hash; if (!txId) { throw new Error('txId is undefined'); } return { txId, txHash, }; } catch (err) { logger.error(`Error submitting proof: ${String(err)}`); throw err; } } } //# sourceMappingURL=proofSubmitter.js.map