diff --git a/src/components/ProgramLoader/Loader.tsx b/src/components/ProgramLoader/Loader.tsx index 9b076306..c49e4d4f 100644 --- a/src/components/ProgramLoader/Loader.tsx +++ b/src/components/ProgramLoader/Loader.tsx @@ -9,9 +9,14 @@ import { setIsProgramEditMode } from "@/store/debugger/debuggerSlice.ts"; import { selectIsAnyWorkerLoading } from "@/store/workers/workersSlice"; import { isSerializedError } from "@/store/utils"; import { ProgramFileUpload } from "@/components/ProgramLoader/ProgramFileUpload.tsx"; +import { bytes } from "@typeberry/block"; +import { selectInitialState } from "@/store/debugger/debuggerSlice.ts"; +import { decodeStandardProgram } from "@typeberry/pvm-debugger-adapter"; +import { RegistersArray } from "@/types/pvm.ts"; export const Loader = ({ setIsDialogOpen }: { setIsDialogOpen?: (val: boolean) => void }) => { const dispatch = useAppDispatch(); + const initialState = useAppSelector(selectInitialState); const [programLoad, setProgramLoad] = useState(); const [error, setError] = useState(); const [isSubmitted, setIsSubmitted] = useState(false); @@ -22,23 +27,75 @@ export const Loader = ({ setIsDialogOpen }: { setIsDialogOpen?: (val: boolean) = setError(""); }, [isLoading]); - const handleLoad = useCallback(async () => { - setIsSubmitted(true); - if (!programLoad) return; + const handleLoad = useCallback( + async (_event: unknown, program?: ProgramUploadFileOutput) => { + setIsSubmitted(true); - dispatch(setIsProgramEditMode(false)); + if (!programLoad && !program) return; - try { - await debuggerActions.handleProgramLoad(programLoad); - setIsDialogOpen?.(false); - } catch (error) { - if (error instanceof Error || isSerializedError(error)) { - setError(error.message); - } else { - setError("Unknown error occured"); + dispatch(setIsProgramEditMode(false)); + + try { + await debuggerActions.handleProgramLoad(program || programLoad); + setIsDialogOpen?.(false); + } catch (error) { + if (error instanceof Error || isSerializedError(error)) { + setError(error.message); + } else { + setError("Unknown error occurred"); + } + } + }, + [dispatch, programLoad, debuggerActions, setIsDialogOpen], + ); + + useEffect(() => { + const searchParams = new URLSearchParams(window.location.search); + + if (searchParams.get("program")) { + const program = searchParams.get("program"); + + try { + // Add 0x prefix if it's not there - we're assuming it's the hex program either way + const hexProgram = program?.startsWith("0x") ? program : `0x${program}`; + const parsedBlob = bytes.BytesBlob.parseBlob(hexProgram ?? ""); + const parsedBlobArray = Array.prototype.slice.call(parsedBlob.raw); + + if (searchParams.get("flavour") === "jam") { + try { + const { code, /*memory,*/ registers } = decodeStandardProgram(parsedBlob.raw, new Uint8Array()); + + handleLoad({ + program: Array.from(code), + name: "custom", + initial: { + regs: Array.from(registers) as RegistersArray, + pc: 0, + pageMap: [], + // TODO: map memory properly + // memory: [...memory], + gas: 10000n, + }, + }); + } catch (e) { + console.warn("Could not load the program from URL", e); + } + } else { + handleLoad(undefined, { + program: parsedBlobArray, + name: "custom", + initial: initialState, + }); + } + + window.history.replaceState({}, document.title, "/"); + } catch (e) { + console.warn("Could not parse the program from URL", e); } } - }, [dispatch, programLoad, debuggerActions, setIsDialogOpen]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( <> diff --git a/src/components/ProgramLoader/ProgramFileUpload.tsx b/src/components/ProgramLoader/ProgramFileUpload.tsx index e5565532..6f8f1511 100644 --- a/src/components/ProgramLoader/ProgramFileUpload.tsx +++ b/src/components/ProgramLoader/ProgramFileUpload.tsx @@ -5,6 +5,8 @@ import { mapUploadFileInputToOutput } from "./utils"; import { decodeStandardProgram } from "@typeberry/pvm-debugger-adapter"; import { RegistersArray } from "@/types/pvm.ts"; import { SafeParseReturnType, z } from "zod"; +import { useAppSelector } from "@/store/hooks"; +import { selectInitialState } from "@/store/debugger/debuggerSlice"; const validateJsonTestCaseSchema = (json: unknown) => { const pageMapSchema = z.object({ @@ -58,6 +60,8 @@ export const ProgramFileUpload = ({ onParseError: (error: string) => void; close?: () => void; }) => { + const initialState = useAppSelector(selectInitialState); + let fileReader: FileReader; const handleFileRead = (e: ProgressEvent) => { @@ -102,12 +106,7 @@ export const ProgramFileUpload = ({ onFileUpload({ program: Array.from(uint8Array), name: "custom", - initial: { - regs: Array.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) as RegistersArray, - pc: 0, - pageMap: [], - gas: 10000n, - }, + initial: initialState, }); } }