From 6b870d2d464ad1cc2c09563ba0893a27d493251e Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Tue, 25 Mar 2025 15:41:29 +0000 Subject: [PATCH 1/4] fix: update url for powersoftau --- examples/confidential-coins/scripts/setup | 2 +- examples/demo-app/core/scripts/setup | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/confidential-coins/scripts/setup b/examples/confidential-coins/scripts/setup index 25698e8a..398b72cd 100755 --- a/examples/confidential-coins/scripts/setup +++ b/examples/confidential-coins/scripts/setup @@ -41,7 +41,7 @@ POWERSOFTAUFILE="${TEST_DIR}/powersOfTau28_hez_final_08.ptau" # Pre-generated powersOfTau from snarkjs # if ! [ -e ${POWERSOFTAUFILE} ] ; then - curl https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_08.ptau --output ${POWERSOFTAUFILE} + curl https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_08.ptau --output ${POWERSOFTAUFILE} fi # We just need the following files from this setup script. diff --git a/examples/demo-app/core/scripts/setup b/examples/demo-app/core/scripts/setup index 00a31d44..36e39298 100755 --- a/examples/demo-app/core/scripts/setup +++ b/examples/demo-app/core/scripts/setup @@ -37,9 +37,8 @@ circom ${TEST_DIR}/circuit.circom --r1cs --wasm --output ${TEST_DIR} POWERSOFTAUFILE="${TEST_DIR}/powersOfTau28_hez_final_08.ptau" # Pre-generated powersOfTau from snarkjs -# if ! [ -e ${POWERSOFTAUFILE} ] ; then - curl https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_08.ptau --output ${POWERSOFTAUFILE} + curl https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_08.ptau --output ${POWERSOFTAUFILE} fi # We just need the following files from this setup script. From 62a9c9a9022bac85f3f33f017d52a007abbf2833 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Thu, 27 Mar 2025 18:07:46 +0000 Subject: [PATCH 2/4] fix: better file handling in daemon stop --- upa/scripts/utils.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/upa/scripts/utils.sh b/upa/scripts/utils.sh index e0b65bdf..30781bcd 100644 --- a/upa/scripts/utils.sh +++ b/upa/scripts/utils.sh @@ -94,13 +94,18 @@ function start_daemon() { # 1 - name function stop_daemon() { - pid_file="$1.pid" - cid_file="$1.cid" if [ "${DOCKER}" == "1" ] ; then + cid_file="$1.cid" + if ! [ -e ${cid_file} ] ; then + echo "$1 has no CID file: ${cid_file}" + return + fi + cid=$(cat ${cid_file}) docker container kill ${cid} rm ${cid_file} else + pid_file="$1.pid" if ! [ -e ${pid_file} ] ; then echo "$1 has no PID file: ${pid_file}" return From 9fcb2a079595273c251e029c1a857dfd29d09504 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Fri, 28 Mar 2025 11:17:16 +0000 Subject: [PATCH 3/4] fix[upa]: in stop_daemon (docker) handle case where server is already stopped --- upa/scripts/utils.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/upa/scripts/utils.sh b/upa/scripts/utils.sh index 30781bcd..b0e9c907 100644 --- a/upa/scripts/utils.sh +++ b/upa/scripts/utils.sh @@ -102,7 +102,9 @@ function stop_daemon() { fi cid=$(cat ${cid_file}) - docker container kill ${cid} + docker container kill ${cid} || \ + echo "Failed stopping container ${cid}. It may have died." + rm ${cid_file} else pid_file="$1.pid" From 0e5e68087c99139733780afc9e6dd4d88763bdb1 Mon Sep 17 00:00:00 2001 From: Duncan Tebbs Date: Wed, 2 Apr 2025 14:59:51 +0100 Subject: [PATCH 4/4] feat[upa]: parse events from tx receipt. --events flag on get-submission --- upa/scripts/test_upa | 2 +- upa/src/sdk/events.ts | 41 +++++++++++++++++++++++++++++++++++ upa/src/tool/getSubmission.ts | 29 +++++++++++++++++++++++-- upa/src/tool/isVerified.ts | 34 +++++++++++++++++++++++++++++ upa/src/tool/query.ts | 7 +++++- 5 files changed, 109 insertions(+), 4 deletions(-) diff --git a/upa/scripts/test_upa b/upa/scripts/test_upa index 4554a68a..cc9f98ad 100755 --- a/upa/scripts/test_upa +++ b/upa/scripts/test_upa @@ -169,7 +169,7 @@ pushd _test_upa # --submission-file submit-multi-4.submission.json # Extract the submissions - upa get-submission `cat submit-1.tx.hash` > submit-1.submission.json + upa get-submission --events `cat submit-1.tx.hash` > submit-1.submission.json upa get-submission `cat submit-multi-4.tx.hash` > submit-multi-4.submission.json multi_4_submissionid=`jq -r .submissionId submit-multi-4.submission.json` diff --git a/upa/src/sdk/events.ts b/upa/src/sdk/events.ts index 12a14d08..7f0a7dd2 100644 --- a/upa/src/sdk/events.ts +++ b/upa/src/sdk/events.ts @@ -122,6 +122,27 @@ export abstract class EventGetterBase< return output; } + public parseTransactionReceipt( + txReceipt: ethers.TransactionReceipt + ): EventSet { + const evName = this.eventName(); + const events: EventOutput[] = []; + for (const log of txReceipt.logs) { + const parsed = this.upa.interface.parseLog(log as unknown as ethers.Log)!; + const name = parsed.name; + if (name === evName) { + events.push(this.parseEvent(parsed as unknown as TypedEventLog)); + } + } + return { + blockNumber: txReceipt.blockNumber, + txHash: txReceipt.hash, + events, + }; + } + + abstract eventName(): string; + // TODO: There should be a generic way to write this. abstract parseEvent(ev: TypedEventLog): EventOutput; } @@ -151,6 +172,10 @@ export class ProofSubmittedEventGetter extends EventGetterBase< super(upa, upa.filters.ProofSubmitted(...args)); } + eventName(): string { + return "ProofSubmitted"; + } + parseEvent( ev: TypedEventLog ): ProofSubmittedEvent.OutputObject { @@ -345,6 +370,10 @@ export class SubmissionVerifiedEventGetter extends EventGetterBase< super(upa, upa.filters.SubmissionVerified(...args)); } + eventName(): string { + return "SubmissionVerified"; + } + parseEvent( ev: TypedEventLog ): SubmissionVerifiedEvent.OutputObject { @@ -416,6 +445,10 @@ export class VKRegisteredEventGetter extends EventGetterBase< super(upa, upa.filters.VKRegistered()); } + eventName(): string { + return "VKRegistered"; + } + parseEvent( ev: TypedEventLog ): VKRegisteredEvent.OutputObject { @@ -439,6 +472,10 @@ export class ChallengeEventGetter extends EventGetterBase< super(upa, upa.filters.Challenge()); } + eventName(): string { + return "Challenge"; + } + // eslint-disable-next-line parseEvent(ev: TypedEventLog): ChallengeEventOutput { return {}; @@ -458,6 +495,10 @@ export class SubmissionChallengeSuccessEventGetter extends EventGetterBase< super(upa, upa.filters.SubmissionChallengeSuccess()); } + eventName(): string { + return "SubmissionChallengeSuccess"; + } + // eslint-disable-next-line parseEvent(ev: TypedEventLog): ChallengeEventOutput { return {}; diff --git a/upa/src/tool/getSubmission.ts b/upa/src/tool/getSubmission.ts index abbab118..4162ad63 100644 --- a/upa/src/tool/getSubmission.ts +++ b/upa/src/tool/getSubmission.ts @@ -1,9 +1,12 @@ -import { command, positional, string } from "cmd-ts"; +import { command, flag, positional, string } from "cmd-ts"; import * as options from "./options"; import * as ethers from "ethers"; import * as config from "./config"; import * as utils from "../sdk/utils"; import { Submission } from "../sdk"; +import { EventSet, ProofSubmittedEventGetter } from "../sdk/events"; +// eslint-disable-next-line +import { ProofSubmittedEvent } from "../../typechain-types/contracts/tests/TestUpgradedUpaVerifier"; export const getSubmission = command({ name: "get-submission", @@ -15,9 +18,18 @@ export const getSubmission = command({ displayName: "tx-id", description: "Tx Id of the submission to retrieve", }), + events: flag({ + long: "events", + description: "Dump event data for the submission", + }), }, description: "Get the on-chain submission information associated with a Tx", - handler: async function ({ chainEndpoint, instance, txId }): Promise { + handler: async function ({ + chainEndpoint, + instance, + txId, + events, + }): Promise { const provider = new ethers.JsonRpcProvider(chainEndpoint); const { verifier } = await config.upaFromInstanceFile(instance, provider); @@ -30,6 +42,19 @@ export const getSubmission = command({ txReceipt ); + // If the events flag is given, dump the event data. + if (events) { + const evGetter = new ProofSubmittedEventGetter(verifier); + const eventSet = evGetter.parseTransactionReceipt(txReceipt); + // Put the event set on an `eventSet` attribute of the submission + // object. + ( + submission as unknown as { + eventSet: EventSet; + } + ).eventSet = eventSet; + } + console.log(utils.JSONstringify(submission)); }, }); diff --git a/upa/src/tool/isVerified.ts b/upa/src/tool/isVerified.ts index c154ec49..467c4bc0 100644 --- a/upa/src/tool/isVerified.ts +++ b/upa/src/tool/isVerified.ts @@ -97,3 +97,37 @@ export const isVerified = command({ process.exit(verified ? 0 : 1); }, }); + +export const isUnitSubmissionVerified = command({ + name: "is-unit-submission", + description: + "Query UPA contract for verification status of a single-proof submission " + + "with the given proofid", + args: { + chainEndpoint: options.chainEndpoint(), + instance: options.instance(), + proofId: positional({ + type: string, + displayName: "proof-id", + description: "Proof Id to verifiy (must be part of single submission)", + }), + + proofReferenceFile: options.proofReferenceFile(), + }, + handler: async function ({ + chainEndpoint, + instance, + proofId, + }): Promise { + const provider = new ethers.JsonRpcProvider(chainEndpoint); + const upa = await config.upaFromInstanceFile(instance, provider); + + const verified = await upa.verifier.getFunction("isProofVerified(bytes32)")( + proofId + ); + + // write 1/0 to stdout and use exit status to indicate validity + console.log(verified ? "1" : "0"); + process.exit(verified ? 0 : 1); + }, +}); diff --git a/upa/src/tool/query.ts b/upa/src/tool/query.ts index ace8d62e..1df3e936 100644 --- a/upa/src/tool/query.ts +++ b/upa/src/tool/query.ts @@ -4,7 +4,11 @@ import { getConfig } from "./getConfig"; import { chainEndpoint, instance } from "./options"; import { ethers } from "ethers"; import { upaFromInstanceFile } from "./config"; -import { isVerified, isSubmissionVerified } from "./isVerified"; +import { + isVerified, + isSubmissionVerified, + isUnitSubmissionVerified, +} from "./isVerified"; import { getAggregatedProofVerifier } from "./aggregatedProofVerifier"; const getVerifierByteCode = command({ @@ -39,5 +43,6 @@ export const query = subcommands({ "verifier-bytecode": getVerifierByteCode, "is-verified": isVerified, "is-submission-verified": isSubmissionVerified, + "is-unit-submission-verified": isUnitSubmissionVerified, }, });