Skip to content

Commit

Permalink
feat: UI for proof generation
Browse files Browse the repository at this point in the history
  • Loading branch information
FilipHarald committed Jul 2, 2023
1 parent bcfd73d commit 161a611
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 10 deletions.
31 changes: 22 additions & 9 deletions packages/nextjs/components/noir/Circuit/CallForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { CallFormInput } from "./CallFormInput";
import { ProofResult } from "./Proof";
import { getFunctionInputKey, getInitialFormState } from "./utilsCircuit";
import { TxReceipt } from "~~/components/scaffold-eth";
import useProofGenerator, { Proof } from "~~/hooks/noir/useProofGenerator";
import { useProvingNotifications } from "~~/hooks/noir/useProvingNotifications";
import { CircuitAbiParameters, CircuitName } from "~~/utils/noir/circuit";
import { notification } from "~~/utils/scaffold-eth";

type TCallFormProps = {
circuitName: CircuitName;
Expand All @@ -11,22 +14,32 @@ type TCallFormProps = {

export const CallForm = ({ circuitName, params }: TCallFormProps) => {
const [form, setForm] = useState<Record<string, any>>(() => getInitialFormState(circuitName, params));
const withNotifications = useProvingNotifications();
const { result, isLoading, generateProof } = useProofGenerator(circuitName, form);
const [displayedGenerationResult, setDisplayedGenerationResult] = useState<Proof>();

// TODO: ...
useEffect(() => {
setDisplayedGenerationResult(result);
}, [result]);

const handleWrite = async () => {
console.log("TODO: handleWrite");
try {
const proofProm = generateProof();
withNotifications(proofProm);
const res = await proofProm;
setDisplayedGenerationResult(res);
} catch (e: any) {
notification.error(e.message);
}
};
//const [displayedTxResult, setDisplayedTxResult] = useState<TransactionReceipt>();
const displayedTxResult = "I am a proof result";

const inputs = params.map((p, index) => {
const key = getFunctionInputKey(circuitName, p, index);
return (
<CallFormInput
key={key}
setForm={updatedFormValue => {
//setDisplayedTxResult(undefined);
setDisplayedGenerationResult(undefined);
setForm(updatedFormValue);
}}
form={form}
Expand All @@ -42,11 +55,11 @@ export const CallForm = ({ circuitName, params }: TCallFormProps) => {
{inputs}
<div className="flex justify-between gap-2">
<div className="flex-grow basis-0">
{displayedTxResult ? <TxReceipt txResult={displayedTxResult} /> : null}
{displayedGenerationResult ? <ProofResult proof={displayedGenerationResult} /> : null}
</div>
</div>
<div className={"flex"}>
<button className={"btn btn-secondary btn-sm"} onClick={handleWrite}>
<button className={`btn btn-secondary btn-sm ${isLoading ? "loading" : ""}`} onClick={handleWrite}>
Generate proof 🧠
</button>
</div>
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/components/noir/Circuit/CallFormInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const CallFormInput = ({ setForm, form, stateObjectKey, param }: CallForm

if (param.type.kind === "string") {
return <InputBase {...inputProps} />;
} else if (param.type.kind === "field") {
// TODO...
} else {
console.error("Unsupported param type:", param.type.kind);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/components/noir/Circuit/CircuitUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const CircuitUI = ({ circuitName, className = "" }: CircuitUIProps) => {
<div className="bg-base-100 rounded-3xl shadow-md shadow-secondary border border-base-300 flex flex-col mt-10 relative">
<div className="h-[5rem] w-[5.5rem] bg-base-300 absolute self-start rounded-[22px] -top-[38px] -left-[1px] -z-10 py-[0.65rem] shadow-lg shadow-base-300">
<div className="flex items-center justify-center space-x-2">
<p className="my-0 text-sm">Verify</p>
<p className="my-0 text-sm">Verify 🔍</p>
</div>
</div>
<div className="p-5 divide-y divide-base-300">
Expand Down
15 changes: 15 additions & 0 deletions packages/nextjs/components/noir/Circuit/Proof.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Proof } from "~~/hooks/noir/useProofGenerator";

export const ProofResult = ({ proof }: { proof: Proof | undefined }) => {
return (
<div className="flex-wrap collapse collapse-arrow mb-2">
<input type="checkbox" className="min-h-0 peer" />
<div className="collapse-title text-sm rounded-3xl peer-checked:rounded-b-none min-h-0 bg-secondary py-1.5">
<strong>Generated proof</strong>
</div>
<div className="collapse-content overflow-auto bg-secondary rounded-t-none rounded-3xl">
<pre className="text-xs pt-4">{JSON.stringify(proof, null, 2)}</pre>
</div>
</div>
);
};
48 changes: 48 additions & 0 deletions packages/nextjs/hooks/noir/useProofGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { CircuitName } from "~~/utils/noir/circuit";

// TODO: where should this live?
export type Proof = string;

let isRunning = false;
const circuitProofs: Partial<
Record<
CircuitName,
{
resultPromise: Promise<Proof>;
result: Proof;
}
>
> = {};

const generateProofWrapper = (circuitName: CircuitName, parsedArgs?: any) => {
console.log("generateProofWrapper", circuitName, parsedArgs);
return async () => {
if (isRunning) throw new Error("A proof generation already in progress");
isRunning = true;
const proofPromise = new Promise<Proof>(resolve => {
setTimeout(() => {
isRunning = false;
const res = "I am a proof result for " + circuitName;
circuitProofs[circuitName]!.result = res;
console.log("proofPromise resolving");
resolve(res);
}, 2000);
});
circuitProofs[circuitName]!.resultPromise = proofPromise;
return proofPromise;
};
};

export default function useProofGenerator(circuitName: CircuitName, form: any) {
if (!circuitProofs[circuitName]) {
circuitProofs[circuitName] = {
resultPromise: new Promise(r => r("hej")),
result: "",
};
}
return {
result: circuitProofs[circuitName]!.result,
isLoading: isRunning,
generateProof: generateProofWrapper(circuitName, form),
};
}
34 changes: 34 additions & 0 deletions packages/nextjs/hooks/noir/useProvingNotifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { notification } from "~~/utils/scaffold-eth";

type TWithNotificationsFunc = (proofGeneration: Promise<string>) => Promise<string>;

const ProofNotification = ({ message }: { message: string }) => {
return (
<div className={`flex flex-col ml-1 cursor-default`}>
<p className="my-0">{message}</p>
</div>
);
};

export const useProvingNotifications = (): TWithNotificationsFunc => {
const fn: TWithNotificationsFunc = async proofGeneration => {
let notificationId = null;
let res = "";
try {
notificationId = notification.loading(<ProofNotification message="Generating proof..." />);
res = await proofGeneration;
notification.remove(notificationId);
notification.success(<ProofNotification message="Proof generated successfully!" />, {
icon: "🎉",
});
} catch (error: any) {
if (notificationId) {
notification.remove(notificationId);
}
console.error("⚡️ ~ file: useProvingNotifications.tsx ~ error", error.stack);
notification.error(error.message);
}
return res;
};
return fn;
};

0 comments on commit 161a611

Please sign in to comment.